【问题标题】:PHP XSLTProcessor transformToXml returns nullPHP XSLTProcessor transformToXml 返回 null
【发布时间】:2015-09-14 08:02:09
【问题描述】:

我正在更新我的脚本以将我们的代码从 Ubuntu 12.04 (PHP 5.3.10) 移动到 Ubuntu 14.04 (PHP 5.5.9),但是 $result = $proc->transformToXml($xml); 一直返回 NULL,我不知道为什么。

  • 我几乎对每个变量/对象都进行了 var_dump() 编辑并检查了它的内容
  • Google 搜索了许多不同的搜索字词

如上所述,这曾经在 Ubuntu 12.04 中工作,并且根据(我能找到的)不同的 PHP 版本之间关于使用的类(DomDocument、XSLTProcessor)没有任何变化。

如何让$result 包含正确解析的 XML 输出?

这是我的 PHP 代码:

$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);

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>

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>

【问题讨论】:

  • (该人删除了他的评论,这是对删除“LIBXML_NOERROR”的回复)这只会抛出PHP Warning: DOMDocument::loadXML(): Namespace prefix vac on &lt;nodename&gt; is not defined in Entity很多次,XML本身似乎仍然正确加载到 DomDocument 中(当我使用 saveXML() 它返回相同的 XML 输出)。 loadXML() 也返回 true,根据 PHPDoc,这意味着它成功加载了 XML。

标签: php xml xslt


【解决方案1】:

您在错误的位置寻找问题。它与PHP无关。 PHP 只使用 libxml2,您最好使用 xsltproc 来检查问题所在。运行:

xsltproc test.xsl test.xml

基本上是SISO的经典案例。 XSLT 只是返回了恰好为 NULL 的操作的正确结果。你为什么要问?这里是您遇到的一系列问题:

  1. 您的 XML 文档中没有“vac”命名空间的定义。您的 XML 完全无效。
  2. 在 xsl:stylesheet 的 XSL 中没有定义“vac”命名空间。您的 XSL 根本不知道“vac”命名空间。所以无论你做什么 vac: 元素都将保持不可见。
  3. 您的 XPath 语句引用了没有限定名称空间的元素:将使用默认名称空间。但是您的 XML 中没有任何具有默认命名空间的元素。因此你得到 NULL - 没有任何处理!

PS:请帮自己一个忙,在您的 XML 文件中使用 &lt;?xml version="1.0" encoding="utf-8"?&gt;。否则你最终会遇到编码问题。

PPS:关于您的评论,根据“PHPDoc 表示它成功加载了 XML”。成功加载并不意味着您的 XML 是正确的。您有充分的理由得到“&lt;nodename&gt; 上的命名空间前缀 vac 未在实体中定义”。

这里是正确的 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>

并纠正 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”命名空间必须同时添加到 XML 和 XSL
  2. XPath 语句然后可以使用它
  3. 我添加了&lt;vac:antwoordTekst&gt;show me!&lt;/vac:antwoordTekst&gt;,因为空元素的样式返回NULL。只是为了展示一些东西。

这些文件的结果是:

show me!
                &lt;p&gt;Lorem Ipsum dolar sit amet&lt;/p&gt;

【讨论】:

  • 命名空间必须是绝对的:也就是说,你不能只使用 standaarden.overheid.nl/vac ,它必须以 / 或者甚至更好的 URI 模式开头,例如 http:// 。请记住,XML 是严格的!
  • 谢谢!还没有深入使用 XML,所以这对我来说是全新的,感谢详尽的解释
  • 为什么 在这种情况下不返回任何东西? XPath 似乎正确,命名空间也设置正确
  • 它确实返回了<p>Lorem Ipsum dolar sat amet</p> - 这就是 CDATA 中的内容
  • 啊,我的命名空间声明仍然不正确(它有一个结尾 /)这很难。
【解决方案2】:

如果其他人遇到这个问题,我必须先utf_encode() 我的$xml_file_contents 才能工作,因为 XML 文档中有特殊字符。将&lt;?xml version="1.0" encoding="UTF-8"?&gt; 声明添加到 XML 文档的顶部似乎并不能帮助解析器处理 utf-8 特殊字符。

【讨论】:

    猜你喜欢
    • 2014-11-11
    • 2011-02-28
    • 2018-12-17
    • 2014-03-27
    • 2015-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多