PHP: различное поведение XSLT-процессора в Windows WRT и Linux - PullRequest
0 голосов
/ 20 ноября 2018

У меня есть этот фрагмент 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 Это желаемый вывод, который фактически получается в результате применения XSLT в Linux:

<?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: это, безусловно, связано с элементом xsl: number, но я не могу понять, как это исправить ...


Редактировать после принятого ответа

Изменяя атрибут xsl:number count на * вместо node() шаблон xsltAte работает должным образом как на Win, так и на Linux.

Вот обновленный код:

<?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>

1 Ответ

0 голосов
/ 20 ноября 2018

В атрибуте select xsl:number используйте * вместо node().

Когда вы используете node(), это может быть элемент, текст, комментарий или узел инструкции обработки.

Когда вы используете *, это только элемент.Это имеет больше смысла при использовании xsl:number.

См. https://xsltfiddle.liberty -development.net / nc4NzRq / 1 для рабочей скрипки.(Спасибо @parfait!)

...