名称空间作为使用 XSLT 处理的文档的变量

Posted

技术标签:

【中文标题】名称空间作为使用 XSLT 处理的文档的变量【英文标题】:Namespace as variable for document being processed with XSLT 【发布时间】:2019-10-01 05:22:40 【问题描述】:

问题如下,我们需要转换 XML 文件,客户给我们发送了 4 个不同的文件,每个文件都有不同的名称,每个文件都有一个唯一的命名空间,但是文档中的元素是相同的。

文件被命名; Supplier_Invoices_1、Supplier_Invoices_2、Supplier_Invoices_3 等没有扩展名,但它们是 XML。

Supplier_Invoices_2 的命名空间是:

xmlns:wd="urn:com.cust.report/Supplier_Invoices_2"

对于发票_1:

"urn:com.cust.report/Supplier_Invoices_1" 

发票_3:

"urn:com.cust.report/Supplier_Invoices_3"

等等等等。

输入 - Supplier_Invoices_2 示例:

<?xml version='1.0' encoding='UTF-8'?>
<wd:Report_Data xmlns:wd="urn:com.cust.report/Supplier_Invoices_2">
    <wd:Report_Entry>
        <wd:CF_LRV_Journal_line_group>
            <wd:Invoice_Number>SI-00026584</wd:Invoice_Number>
            <wd:Supplier_s_Invoice_Number>19031275</wd:Supplier_s_Invoice_Number>
            <wd:Invoice_Date>2019-03-18-07:00</wd:Invoice_Date>
            <wd:Supplier wd:Descriptor="Company X">
                <wd:ID wd:type="WID">d4e89886417501a66aadebf4570da733</wd:ID>
                <wd:ID wd:type="Supplier_Reference_ID">SUP924</wd:ID>
                <wd:ID wd:type="Supplier_ID">S-00000461</wd:ID>
            </wd:Supplier>
            <wd:Transaction_Debit_minus_Credit>1956.92</wd:Transaction_Debit_minus_Credit>          
        </wd:CF_LRV_Journal_line_group>
    </wd:Report_Entry>
</wd:Report_Data>  

XSLT:

<xsl:stylesheet version="2.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:wd="urn:com.cust.report/Supplier_Invoices_2">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">        
     <xsl:param name="XSLPath" select="base-uri()"/>
        <message>
            <data>
                <xsl:for-each select="/wd:Report_Data/wd:Report_Entry/wd:CF_LRV_Journal_line_group" >
                    <Documents>
                        <row>
                            <path>
                                <xsl:value-of select="tokenize($XSLPath,'/')[last()]" />
                            </path>
                            <CardCode>
                                <xsl:value-of select="./wd:Supplier/wd:ID[@wd:type='Supplier_ID']"/>
                            </CardCode>
                        </row>
                    </Documents>
                    <Document_Lines>
                        <row>
                            <Price>
                                <xsl:value-of select="./wd:Transaction_Debit_minus_Credit" />
                            </Price>
                        </row>
                    </Document_Lines>
                </xsl:for-each>
            </data>
        </message>
    </xsl:template>
</xsl:stylesheet>  

输出:

<?xml version="1.0" encoding="UTF-8"?>
<message xmlns:wd="urn:com.cust.report/Supplier_Invoices_2">
   <data>
      <Documents>
         <row>
            <path>Supplier_Invoices_2</path>
            <CardCode>S-00000461</CardCode>
         </row>
      </Documents>
      <Document_Lines>
         <row>
            <Price>1956.92</Price>
         </row>
      </Document_Lines>
   </data>
</message>

我的问题,如何将我的 XSL 文档中的命名空间设置为它正在处理的文档的变量?

我将 xsl:param 添加到我的 XSL 中。顶部文档前 5 行如下所示:

<xsl:stylesheet version="2.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:wd="urn:com.cust.report/$npath" >
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">        
     <xsl:param name="XSLPath" select="base-uri()"/>
     <xsl:param name="npath" select="tokenize($XSLPath,'/')[last()]" />

输出:

<?xml version="1.0" encoding="UTF-8"?>
<message xmlns:wd="urn:com.cust.report/$npath">
   <data/>
</message>

任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

在 XSLT/XPath 2 及更高版本中,您可以使用命名空间通配符 *:foo 在任何命名空间中选择具有本地名称 foo 的元素,因此如果您使用例如*:Report_Data 而不是 wd:Report_Data 你应该能够处理相同结构但具有不同命名空间的文档。

作为替代方案,您可以在链中使用样式表,将不同命名空间中的输入的命名空间标准化为一个公共命名空间,这样您就可以在第二个样式表中使用公共命名空间。

【讨论】:

嗨,马丁,感谢您的快速回复。我宁愿选择第一个选项,如果我理解正确,我可以删除命名空间:xmlns:wd="urn:com.cust.report/Supplier_Invoices_2" 然后用* 查找/替换所有wd: 好的,这行得通。 &lt;xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" &gt; &lt;xsl:output method="xml" encoding="UTF-8" indent="yes"/&gt; &lt;xsl:template match="/"&gt; &lt;xsl:param name="XSLPath" select="base-uri()"/&gt; &lt;message&gt; &lt;data&gt; &lt;xsl:for-each select="/*:Report_Data/*:Report_Entry/*:CF_LRV_Journal_line_group" &gt; ... etc 非常感谢。

以上是关于名称空间作为使用 XSLT 处理的文档的变量的主要内容,如果未能解决你的问题,请参考以下文章

XSLT:如何删除同义名称空间

名称空间感知文档返回空NodeList

如何使用 XSLT 从 XML 中删除名称空间

如何在 XSLT 输出中控制名称空间前缀(特别是默认名称空间)?

如何使用 XSLT 为所有元素和属性添加名称空间和前缀?

如何使用 XSLT 向 XML 有效负载添加不同的名称空间