About encodings & entities in PHP5 using DOM XML/XSLT

[email protected] (Vivian Steller) Sun, 03 Oct 2004 19:55:34 +0200
Newsgroups php.xml.dev
Organization eecoo
Message-ID <[email protected]>
Handling encodings and entities in XML/XSL Documents is a bit tricky for
beginners, I think. Thus I want to present what I found out, hopefully in a
simpler manner.

First it seems to me that the current DOM Implementation of PHP (5.0.3) and
libxml2 respectively do not handle something else then UTF-8 encoding. Even
so if you write the encoding as second parameter on construction of the
document:

$doc = new DOMDocument("1.0", "ISO-8859-1");

Nevertheless, error messages like 'no propper utf-8 encoding in file...'
while parsing with $doc->loadXXX() occur.

Maybe the behaviour is like 
>Jirka Kosek wrote:
>
>> I know that in PHP4 and older xml_parser used expat parser as an 
>> underlying implementation and was limited to characters in ISO-8859-1. 
>> According to documentation in PHP5 xml_parser should be built on the top 
>> of libxml2. Thus I thought that it would support all encodings supported 
>> by libxml2. My experience is that characters outside of ISO-8859-1 are 
>> replaced by ? in the same way as expat does it.
>
>Never mind. I figured out that layering on top of libxml2 is little 
>non-intuitive, but if I specify optional parameter on 
>xml_parser_create() I can read document in whatever encoding supported 
>by libxml2 and this encoding is internally converted into utf-8.
>
>$parser = xml_parser_create("utf-8");

Anyway, I found out that everything works fine with encodings (i.e. german
umlaute etc.)/entities if you consider the following issues:

- save your .xml, .xsl files in the right charset: utf-8 encoded. (TextPad
for example enables you to choose between ansi, utf8, dos,... this prevends
the parser from throwing an exception like mentioned above.

- use a dtd to resolve the xhtml entities:
http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent
then you can use &nbsp;, &uuml; etc. easaly. Maybe you get problems with xml
editors like xmlspy because of an incomplete dtd.. i've no idea how to
avoid this...

- set $doc->resolveExternals (to handle external dtd declarations) and
$doc->substituteEntities (needed if you want to use entities within
transformations) to true. XSL can handle character encodings like &#160;
but NOT entity references like &nbsp; (thus substitute them)

- use $doc::load() or loadXML() to parse your input xml/xsl file, but
$doc::saveHTML() to serialize the DOM to well-formed XHTML code. then the
result will be in the right manner, i.e. &#160; will be transformed to
&nbsp; again...


Finally the whole thing in action:

Save this UTF-8 ENCODED!!
****************** XML SOURCE *******************
<!DOCTYPE html PUBLIC "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent">
or better download the file and do
<!DOCTYPE html SYSTEM "DTD/xhtml-lat1.ent">

<html>
        <body>
                My&nbsp;Test
        </body>
</html>
 


Save this UTF-8 ENCODED!!
****************** XSL SOURCE *******************
<?xml version="1.0"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="html" omit-xml-declaration="no"/>
        <xsl:template match="/">
                This is&#160; <!-- character encodings do not need any dtd! -->
                <xsl:apply-templates/>
        </xsl:template>
</xsl:stylesheet>



****************** PHP SOURCE CODE *******************
<?php
        $doc = new DOMDocument();
        $doc->resolveExternals = true;
        $doc->substituteEntities = true;
        $doc->loadXML($xml_source);
        
        $xsl = new DOMDOcument();
        $xsl->resolveExternals = true;
        $xsl->substituteEntities = false;
        $xsl->load("xsl_source.xsl");
        
        $proc = new XSLTProcessor();
        $proc->importStylesheet($xsl);
        print($proc->transformToDoc($doc)->saveHTML());
?>

Maybe this helps someone. If you got some more infos, please let me know.

Cya
vivi