xml — PHP: различное поведение XSLT-процессора в Windows WRT и 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:

Окна:

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 Doc, который дает разные результаты в 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() шаблон xslt работает как положено как в 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>

4

Решение

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

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

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

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

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]