我有这个 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 wrt 与 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>
以及在 win 和 linux XSLT 中给出不同结果的 XML Doc:
<?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 放置而不是相对索引:它肯定与 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>