3

I am working on updating my script to move our code from Ubuntu 12.04 (PHP 5.3.10) to Ubuntu 14.04 (PHP 5.5.9), however $result = $proc->transformToXml($xml); keeps returning NULL and I don't know why.

  • I've var_dump()-ed pretty much every variable/object and checked it's contents
  • Googled on many different search terms

As stated this used to work in Ubuntu 12.04 and according to (what I can find) there has been no changes between different PHP versions regarding the used classes (DomDocument, XSLTProcessor).

How can I get $result to contain the correctly parsed XML output?

This is my PHP code:

$xml = new DomDocument();
$xml->loadXML($xml_file_contents, LIBXML_NOERROR);
$xml->normalizeDocument(); //Whether included or left out doesn't seem to make a difference

$xsl = new DomDocument();
$xsl->loadXML($xsl_file_contents);

$proc = new XSLTProcessor();
$proc->importStylesheet($xsl);

$result = $proc->transformToXml($xml);

The XML:

<vac:body>
    <vac:kanaal type="generiek">
        <vac:vraag>Lorem Ipsum dolar sit amet</vac:vraag>
        <vac:antwoord
            xmlns="http://www.w3.org/1999/xhtml">
            <vac:antwoordTekst/>
            <vac:antwoordTekstErvoor/>
            <vac:antwoordTekstOrigineel/>
            <vac:antwoordTekstErna/>
            <vac:antwoordProductVeld>
                <![CDATA[<p>Lorem Ipsum dolar sit amet</p>]]>
            </vac:antwoordProductVeld>
            <vac:antwoordAdres/>
        </vac:antwoord>
        <vac:toelichting
            xmlns="http://www.w3.org/1999/xhtml">
            <![CDATA[]]>
        </vac:toelichting>
        <vac:onderwaterantwoord>
            <vac:onderwaterantwoordTekst/>
            <vac:onderwaterantwoordProductVeld/>
        </vac:onderwaterantwoord>
        <vac:formulieren/>
        <vac:contactinfo/>
    </vac:kanaal>
    <vac:verwijzingProduct resourceIdentifier="1337">Lorem ipsum</vac:verwijzingProduct>
    <vac:verwijzingVac resourceIdentifier="1337-01">Lorem Ipsum dolar sit amet</vac:verwijzingVac>
    <vac:verwijzingVac resourceIdentifier="1337-02">Lorem ipsum dolar sit amet</vac:verwijzingVac>
</vac:body>

And the XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes" />

    <xsl:template match="/">

        <xsl:call-template name="text">
            <xsl:with-param name="node" select="/body/kanaal/antwoord/antwoordTekst" />
        </xsl:call-template>

        <xsl:call-template name="text">
            <xsl:with-param name="node" select="/body/kanaal/antwoord/antwoordProductVeld" />
        </xsl:call-template>

        <xsl:call-template name="address">
            <xsl:with-param name="node" select="/body/kanaal/antwoord/antwoordAdres" />
        </xsl:call-template>

        <xsl:if test="/body/kanaal/verwijzingOverigeInfo" >
            <ul>
                <xsl:for-each select="/body/kanaal/verwijzingOverigeInfo" >
                    <xsl:call-template name="moreinfo">
                        <xsl:with-param name="node" select="self::node()" />
                    </xsl:call-template>
                </xsl:for-each>
            </ul>
        </xsl:if>

    </xsl:template>

    <xsl:template name="text">
        <xsl:param name="node" />
        <xsl:if test="normalize-space($node/text())">
            <xsl:value-of select="$node"/>
        </xsl:if>
    </xsl:template>

    <xsl:template name="address">
        <xsl:param name="node" />

        <xsl:for-each select="$node/instantie">
            <p class="vac_address">
                <xsl:for-each select="*">
                    <xsl:call-template name="address_element"/>
                </xsl:for-each>
            </p>
        </xsl:for-each>
    </xsl:template>

    <xsl:template name="address_element">
        <xsl:if test=". != ''">
            <xsl:element name="span">
                <xsl:attribute name="class">
                    <xsl:value-of select ="name(.)"/>
                </xsl:attribute>
                <xsl:value-of select="." disable-output-escaping="yes"/>
            </xsl:element>
        </xsl:if>
    </xsl:template>

    <xsl:template name="moreinfo">
        <xsl:param name="node" />

            <li>
                <xsl:element name="a">
                    <xsl:attribute name="href">
                        <xsl:value-of select="$node/@resourceIdentifier" />
                    </xsl:attribute>
                    <xsl:value-of select="$node" />
                </xsl:element>
            </li>
    </xsl:template>

</xsl:stylesheet>
1
  • (the person removed his comment, this was a reply to removing "LIBXML_NOERROR") That only throws PHP Warning: DOMDocument::loadXML(): Namespace prefix vac on <nodename> is not defined in Entity a bunch of times, the XML itself seems to be still correctly beeing loaded into the DomDocument (when I use saveXML() it returns the same XML output). The loadXML() also returns true which according to the PHPDoc means it loaded the XML succesfully. Commented Sep 14, 2015 at 9:20

2 Answers 2

3

You looking for the issue in the wrong spot. It has nothing to do with PHP. PHP just uses libxml2 and you better off to resort to xsltproc to check what is wrong. Run:

xsltproc test.xsl test.xml

Basically it is classic case of SISO. XSLT just returned proper result of the operation which happens to be NULL. Why you would ask? Here the flurry of the problems you have:

  1. No definition for 'vac' namespace in your XML document. Your XML is plain invalid.
  2. No definition for 'vac' namespace in your XSL in xsl:stylesheet . Your XSL is not aware of 'vac' namespace at all. So no matter what you do vac: elements will remain invisible.
  3. Your XPath statements refer to elements without qualified namespace: default namespace will be used. But you don't have any elements with default namespace in your XML. Hence you get NULL - NOTHING TO PROCESS!

PS: please do yourself a favour and use <?xml version="1.0" encoding="utf-8"?> in your XMLs. Otherwise you eventually run into encoding issues.

PPS: in regards to your comment that according "PHPDoc means it loaded the XML successfully". Successful load does not mean that your XML is correct. You got "Namespace prefix vac on <nodename> is not defined in Entity" for good reason.

Here the correct XML:

<?xml version="1.0" encoding="utf-8"?>
<vac:body xmlns:vac="http://standaarden.overheid.nl/vac">
    <vac:kanaal type="generiek">
        <vac:vraag>Lorem Ipsum dolar sit amet</vac:vraag>
        <vac:antwoord
            xmlns="http://www.w3.org/1999/xhtml">
            <vac:antwoordTekst>show me!</vac:antwoordTekst>
            <vac:antwoordTekstErvoor/>
            <vac:antwoordTekstOrigineel/>
            <vac:antwoordTekstErna/>
            <vac:antwoordProductVeld>
                <![CDATA[<p>Lorem Ipsum dolar sit amet</p>]]>
            </vac:antwoordProductVeld>
            <vac:antwoordAdres/>
        </vac:antwoord>
        <vac:toelichting
            xmlns="http://www.w3.org/1999/xhtml">
            <![CDATA[]]>
        </vac:toelichting>
        <vac:onderwaterantwoord>
            <vac:onderwaterantwoordTekst/>
            <vac:onderwaterantwoordProductVeld/>
        </vac:onderwaterantwoord>
        <vac:formulieren/>
        <vac:contactinfo/>
    </vac:kanaal>
    <vac:verwijzingProduct resourceIdentifier="1337">Lorem ipsum</vac:verwijzingProduct>
    <vac:verwijzingVac resourceIdentifier="1337-01">Lorem Ipsum dolar sit amet</vac:verwijzingVac>
    <vac:verwijzingVac resourceIdentifier="1337-02">Lorem ipsum dolar sit amet</vac:verwijzingVac>
</vac:body>

and correct XSL:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:vac="http://standaarden.overheid.nl/vac">
    <xsl:output method="xml" omit-xml-declaration="yes" />

    <xsl:template match="/">

        <xsl:call-template name="text">
            <xsl:with-param name="node" select="/vac:body/vac:kanaal/vac:antwoord/vac:antwoordTekst" />
        </xsl:call-template>

        <xsl:call-template name="text">
            <xsl:with-param name="node" select="/vac:body/vac:kanaal/vac:antwoord/vac:antwoordProductVeld" />
        </xsl:call-template>

        <xsl:call-template name="address">
            <xsl:with-param name="node" select="/vac:body/vac:kanaal/vac:antwoord/vac:antwoordAdres" />
        </xsl:call-template>

        <xsl:if test="/vac:body/vac:kanaal/vac:verwijzingOverigeInfo" >
            <ul>
                <xsl:for-each select="/vac:body/vac:kanaal/vac:verwijzingOverigeInfo" >
                    <xsl:call-template name="moreinfo">
                        <xsl:with-param name="node" select="self::node()" />
                    </xsl:call-template>
                </xsl:for-each>
            </ul>
        </xsl:if>

    </xsl:template>

    <xsl:template name="text">
        <xsl:param name="node" />
        <xsl:if test="normalize-space($node/text())">
            <xsl:value-of select="$node/text()"/>
        </xsl:if>
    </xsl:template>

    <xsl:template name="address">
        <xsl:param name="node" />

        <xsl:for-each select="$node/vac:instantie">
            <p class="vac_address">
                <xsl:for-each select="*">
                    <xsl:call-template name="address_element"/>
                </xsl:for-each>
            </p>
        </xsl:for-each>
    </xsl:template>

    <xsl:template name="address_element">
        <xsl:if test=". != ''">
            <xsl:element name="span">
                <xsl:attribute name="class">
                    <xsl:value-of select ="name(.)"/>
                </xsl:attribute>
                <xsl:value-of select="." disable-output-escaping="yes"/>
            </xsl:element>
        </xsl:if>
    </xsl:template>

    <xsl:template name="moreinfo">
        <xsl:param name="node" />

            <li>
                <xsl:element name="a">
                    <xsl:attribute name="href">
                        <xsl:value-of select="$node/@resourceIdentifier" />
                    </xsl:attribute>
                    <xsl:value-of select="$node" />
                </xsl:element>
            </li>
    </xsl:template>

</xsl:stylesheet>
  1. 'vac' namespace MUST be added to both XML and XSL
  2. XPath statements then can use it
  3. I have added <vac:antwoordTekst>show me!</vac:antwoordTekst> because styling of empty element returns NULL. Just to throw something to show.

Result of these files is:

show me!
                &lt;p&gt;Lorem Ipsum dolar sit amet&lt;/p&gt;
Sign up to request clarification or add additional context in comments.

5 Comments

Namespaces MUST be absolute: ie you cannot use just standaarden.overheid.nl/vac , it must be either prepended with / or even better with URI schema such as http:// . Remember that XML is STRICT!
Thanks! Haven't worked with XML this deep yet so this is all new to me, appreciate the thorough explanation
Why doesn't <vac:antwoordProductVeld> return anything in this case though? the XPath seems correct and the namespaces are set correctly too
It does return &lt;p&gt;Lorem Ipsum dolar sit amet&lt;/p&gt; - that's what sits inside CDATA
Ah, my namespace declaration was still incorrect (it had an ending /) this is tough.
0

In case anyone else runs into this problem, I had to utf_encode() my $xml_file_contents before it would work because there were special characters in the XML document. Adding the <?xml version="1.0" encoding="UTF-8"?> declaration to the top of the XML document did not seem to help the parser handle the utf-8 special characters.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.