PHP:XSLT 处理器在 Windows WRT 到 Linux 中的不同行为

PHP : different behaviour of XSLT Processor in Windows WRT to Linux

我有这个 php 片段:

$xsltPath = $argv[1];
$xmlPath = $argv[2];

$xslt = file_get_contents($xsltPath);
$xml = file_get_contents($xmlPath);

$templateCMSObj = new \DOMDocument();
$templateCMSObj->loadXML($xslt);
$ekbXMLObj = new \DOMDocument();
$ekbXMLObj->loadXML($xml);
$proc = new \XSLTProcessor();
$proc->importStylesheet($templateCMSObj);
$html = $proc->transformToXML($ekbXMLObj);
echo($html);
exit;

它只是将 XSLT 应用于给定的 XML 文档。

当我将下面的 XSLT 应用于同一个 XML 文档时,我得到了 Windows 与 Linux PHP 版本不同的行为。

这里是 php 和 libxml 版本详细信息:

Windows:

PHP 7.1.6 (cli) (built: Jun  8 2017 02:06:32) ( ZTS MSVC14 (Visual C++ 2015) x86 )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies

XML Support => active
XML Namespace Support => active
libxml2 Version => 2.9.4
XMLReader => enabled
XMLWriter => enabled
XSL => enabled
libxslt Version => 1.1.29
libxslt compiled against libxml Version => 2.9.4
EXSLT => enabled
libexslt Version => 0.8.17

Linux:

PHP 7.0.32-1~dotdeb+8.1 (cli) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.0.32-1~dotdeb+8.1, Copyright (c) 1999-2017, by Zend Technologies
    with Xdebug v2.5.5, Copyright (c) 2002-2017, by Derick Rethans

XML Support => active
XML Namespace Support => active
libxml2 Version => 2.9.1
XMLReader => enabled
XMLWriter => enabled
XSL => enabled
libxslt Version => 1.1.28
libxslt compiled against libxml Version => 2.9.1
EXSLT => enabled
libexslt Version => 1.1.28

这是 XSLT 代码:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="http://new.webservice.namespace">
    <xsl:output method="xml" version="1.0" indent="yes"/>
    <xsl:param name="searchPath" select="11"/>
    <xsl:variable name="slash" select="'/'"/>
    <xsl:variable name="dot" select="'.'"/>
    <xsl:variable name="open_bracket" select="'{'"/>
    <xsl:variable name="closed_bracket" select="'}'"/>
    <xsl:template match="/">
        <ns:flat_pallet>
            <xsl:attribute name="tipo"><xsl:value-of select="//ns:EKB_piatto/@tipo"/></xsl:attribute>
            <xsl:apply-templates select=".//ns:gruppo_logico/ns:versione/ns:contenuto/ns:riferimento_oi"/>
        </ns:flat_pallet>
    </xsl:template>

    <!--restituisco tipo del box e l'indice relativo a nel sottoalbero-->
    <xsl:template match="ns:gruppo_logico">
        <xsl:variable name="tipo">
            <xsl:value-of select="@tipo"/>
        </xsl:variable>
        <xsl:variable name="index">
            <xsl:number level="single" count="node()[@tipo=$tipo]" format="1"/>
        </xsl:variable>
        <xsl:value-of select="normalize-space($tipo)" disable-output-escaping="yes"/>
        <xsl:value-of select="$open_bracket"/>
        <xsl:value-of select="$index -1" disable-output-escaping="yes"/>
        <xsl:value-of select="$closed_bracket"/>
        <xsl:value-of select="$slash"/>
    </xsl:template>
    <!--quando sono in una unit risalgo i box progenitori-->
    <xsl:template match="ns:riferimento_oi">
        <xsl:variable name="tipoUnit" select="./ns:tipo"/>
        <xsl:variable name="index">
            <xsl:number level="single" count="node()[node()/ns:tipo=$tipoUnit]" format="1"/>
        </xsl:variable>
        <xsl:variable name="labelPath">
            <xsl:apply-templates select="ancestor::ns:gruppo_logico"/>
            <xsl:value-of select="$tipoUnit"/>
            <xsl:value-of select="$open_bracket"/>
            <xsl:value-of select="$index -1"/>
            <xsl:value-of select="$closed_bracket"/>
        </xsl:variable>
        <xsl:copy>
            <xsl:attribute name="labelPath"><xsl:value-of select="$labelPath" disable-output-escaping="yes"/></xsl:attribute>
            <xsl:attribute name="unitIndex"><xsl:value-of select="$index" disable-output-escaping="yes"/></xsl:attribute>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="@*|node()">
        <!-- just copy all my attributes and child nodes, except if there's a better template for some of them -->
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!--template per rimuovere nodi vuoti-->
    <xsl:template match="*[not(@*|*|comment()|processing-instruction()) and normalize-space()='']"/>
</xsl:stylesheet>

而 XML 文档在 win 和 linux 中给出了不同的结果 XSLT:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns:dettaglioFormEKBSOUT xmlns:ns="http://new.webservice.namespace">
    <ns:EKB_piatto>
        <ns:campo_GL>
            <ns:gruppo_logico tipo="Standard">
                <ns:versione id="1">
                    <ns:contenuto>
                        <ns:riferimento_oi>
                            <ns:tipo>Standard</ns:tipo>
                            <ns:natura_OI>
                                <ns:UNI>2.1</ns:UNI>
                            </ns:natura_OI>
                        </ns:riferimento_oi>
                    </ns:contenuto>
                    <ns:contenuto>
                        <ns:riferimento_oi>
                            <ns:tipo>Standard</ns:tipo>
                            <ns:natura_OI>
                                <ns:UNI>2.2</ns:UNI>
                            </ns:natura_OI>
                        </ns:riferimento_oi>
                    </ns:contenuto>
                </ns:versione>
            </ns:gruppo_logico>
            <ns:gruppo_logico tipo="Standard_due">
                <ns:versione id="1">
                    <ns:contenuto>
                        <ns:riferimento_oi>
                            <ns:tipo>Standard</ns:tipo>
                            <ns:natura_OI>
                                <ns:UNI>2.1</ns:UNI>
                            </ns:natura_OI>
                        </ns:riferimento_oi>
                    </ns:contenuto>
                    <ns:contenuto>
                        <ns:riferimento_oi>
                            <ns:tipo>Standard_due</ns:tipo>
                            <ns:natura_OI>
                                <ns:UNI>2.2</ns:UNI>
                            </ns:natura_OI>
                        </ns:riferimento_oi>
                    </ns:contenuto>
                </ns:versione>
            </ns:gruppo_logico>
        </ns:campo_GL>
    </ns:EKB_piatto>
</ns:dettaglioFormEKBSOUT>

Linux输出 这是在 Linux:

上应用 XSLT 实际产生的期望输出
<?xml version="1.0"?>
<ns:flat_pallet xmlns:ns="http://new.webservice.namespace" tipo="">
    <ns:riferimento_oi labelPath="Standard{0}/Standard{0}" unitIndex="1">
        <ns:tipo>Standard</ns:tipo>
        <ns:natura_OI>
            <ns:UNI>2.1</ns:UNI>
        </ns:natura_OI>
    </ns:riferimento_oi>
    <ns:riferimento_oi labelPath="Standard{0}/Standard{1}" unitIndex="2">
        <ns:tipo>Standard</ns:tipo>
        <ns:natura_OI>
            <ns:UNI>2.2</ns:UNI>
        </ns:natura_OI>
    </ns:riferimento_oi>
    <ns:riferimento_oi labelPath="Standard_due{0}/Standard{0}" unitIndex="1">
        <ns:tipo>Standard</ns:tipo>
        <ns:natura_OI>
            <ns:UNI>2.1</ns:UNI>
        </ns:natura_OI>
    </ns:riferimento_oi>
    <ns:riferimento_oi labelPath="Standard_due{0}/Standard_due{0}" unitIndex="1">
        <ns:tipo>Standard_due</ns:tipo>
        <ns:natura_OI>
            <ns:UNI>2.2</ns:UNI>
        </ns:natura_OI>
    </ns:riferimento_oi>
</ns:flat_pallet>

Windows输出 这是在 Windows:

上产生的错误结果
<?xml version="1.0"?>
<ns:flat_pallet xmlns:ns="http://new.webservice.namespace" tipo="">
    <ns:riferimento_oi labelPath="Standard{0}/Standard{0}" unitIndex="1">
        <ns:tipo>Standard</ns:tipo>
        <ns:natura_OI>
            <ns:UNI>2.1</ns:UNI>
        </ns:natura_OI>
    </ns:riferimento_oi>
    <ns:riferimento_oi labelPath="Standard{0}/Standard{1}" unitIndex="2">
        <ns:tipo>Standard</ns:tipo>
        <ns:natura_OI>
            <ns:UNI>2.2</ns:UNI>
        </ns:natura_OI>
    </ns:riferimento_oi>
    <ns:riferimento_oi labelPath="Standard_due{NaN}/Standard{0}" unitIndex="1">
        <ns:tipo>Standard</ns:tipo>
        <ns:natura_OI>
            <ns:UNI>2.1</ns:UNI>
        </ns:natura_OI>
    </ns:riferimento_oi>
    <ns:riferimento_oi labelPath="Standard_due{NaN}/Standard_due{NaN}" unitIndex="">
        <ns:tipo>Standard_due</ns:tipo>
        <ns:natura_OI>
            <ns:UNI>2.2</ns:UNI>
        </ns:natura_OI>
    </ns:riferimento_oi>
</ns:flat_pallet>

问题在于 NaN put 而不是相对索引:它肯定与 xsl:number 元素有关,但我不知道如何解决这个问题...


接受答案后编辑

通过将 xsl:number count 属性更改为 * 而不是 node() xslt 模板在 Win 和 Linux.[=25 上都可以正常工作=]

这是更新后的代码:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="http://new.webservice.namespace">
    <xsl:output method="xml" version="1.0" indent="yes"/>
    <xsl:param name="searchPath" select="11"/>
    <xsl:variable name="slash" select="'/'"/>
    <xsl:variable name="dot" select="'.'"/>
    <xsl:variable name="open_bracket" select="'{'"/>
    <xsl:variable name="closed_bracket" select="'}'"/>
    <xsl:template match="/">
        <ns:flat_pallet>
            <xsl:attribute name="tipo"><xsl:value-of select="//ns:EKB_piatto/@tipo"/></xsl:attribute>
            <xsl:apply-templates select=".//ns:gruppo_logico/ns:versione/ns:contenuto/ns:riferimento_oi"/>
        </ns:flat_pallet>
    </xsl:template>

    <!--restituisco tipo del box e l'indice relativo a nel sottoalbero-->
    <xsl:template match="ns:gruppo_logico">
        <xsl:variable name="tipo">
            <xsl:value-of select="@tipo"/>
        </xsl:variable>
        <xsl:variable name="index">
            <xsl:number level="single" count="*[@tipo=$tipo]" format="1"/>
        </xsl:variable>
        <xsl:value-of select="normalize-space($tipo)" disable-output-escaping="yes"/>
        <xsl:value-of select="$open_bracket"/>
        <xsl:value-of select="$index -1" disable-output-escaping="yes"/>
        <xsl:value-of select="$closed_bracket"/>
        <xsl:value-of select="$slash"/>
    </xsl:template>
    <!--quando sono in una unit risalgo i box progenitori-->
    <xsl:template match="ns:riferimento_oi">
        <xsl:variable name="tipoUnit" select="./ns:tipo"/>
        <xsl:variable name="index">
            <xsl:number level="single" count="*[*/ns:tipo=$tipoUnit]" format="1"/>
        </xsl:variable>
        <xsl:variable name="labelPath">
            <xsl:apply-templates select="ancestor::ns:gruppo_logico"/>
            <xsl:value-of select="$tipoUnit"/>
            <xsl:value-of select="$open_bracket"/>
            <xsl:value-of select="$index -1"/>
            <xsl:value-of select="$closed_bracket"/>
        </xsl:variable>
        <xsl:copy>
            <xsl:attribute name="labelPath"><xsl:value-of select="$labelPath" disable-output-escaping="yes"/></xsl:attribute>
            <xsl:attribute name="unitIndex"><xsl:value-of select="$index" disable-output-escaping="yes"/></xsl:attribute>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="@*|node()">
        <!-- just copy all my attributes and child nodes, except if there's a better template for some of them -->
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!--template per rimuovere nodi vuoti-->
    <xsl:template match="*[not(@*|*|comment()|processing-instruction()) and normalize-space()='']"/>
</xsl:stylesheet>

xsl:numberselect 属性中,使用 * 而不是 node()

当您使用 node() 时,它可以是元素、文本、注释或处理指令节点。

当您使用 * 时,那只是一个元素。这在您使用 xsl:number.

时更有意义

请参阅 https://xsltfiddle.liberty-development.net/nc4NzRq/1 了解有效的 fiddle。 (感谢@parfait!)