且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

XML 命名空间抛弃了我的 XSLT

更新时间:2023-11-24 16:26:04

XPath 是您用来匹配特定元素的 XSLT 的一部分,它对名称空间敏感.当你有一个像 MyNameSpace/Table_1/Address 这样的 XPath 时,你匹配的元素没有任何 XML 命名空间;即任何元素 Address 是任何元素 Table_1 的子元素,它是任何元素 MyNameSpace 的子元素,它是当前上下文节点的子元素.>

需要添加命名空间前缀;例如:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"xmlns:z="http://schemas.microsoft.com/dynamics/2006/02/documents/MyNameSpace">...<xsl:value-of select="z:MyNameSpace/z:Table_1/z:Address"/>

不幸的是,XSLT 1.0 在评估 XPath 时没有考虑当前的默认名称空间,因此您不能设置默认名称空间并完成它;你真的需要一个命名空间前缀.

如果您可以使用 XSLT 2.0,您可以使用 xpath-default-namespace 属性为 XPath 查询中引用的元素设置默认命名空间.(XSLT 2.0 在很多小方面更实用,像这样...)

I have an xml document with a name space that looks similar to this, I just simplified it for the sake of asking the question.

<MyNameSpace xmlns="http://schemas.microsoft.com/dynamics/2006/02/documents/MyNameSpace">
<IDmain>ins</IDmain>
    <Table_1 class="entity">
        <Address>Oak Park Drive</BillingProviderAddress>
        <City>Lake Elizabeth</BillingProviderCity>
        <Name>Corporation</BillingProviderOrgName>
        <InvoiceLine class ="entity">
            <DateService>1234</DateService>
        </InvoiceLine>
    <Table_1>
</MyNameSpace>

I then created an XSLT here. I understand its ugly, I'm not an XSLT expert but this was one of those "Just solve the problem" moments.

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">

<xsl:variable name="vPrefix">
<xsl:value-of select="MyNameSpace/Table_1/Address"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="MyNameSpace/Table_1/City"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="MyNameSpace/Table_1/Name"/>
<xsl:text>|</xsl:text>
</xsl:variable>

<xsl:for-each select="MyNameSpace/Table_1/InvoiceLine">
        <xsl:value-of select="$vPrefix"/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="DateService"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Now, The XSLT does exactly what I want it to, the problem is, my test data include this funky namespace at the top of the XML document.

xmlns="http://schemas.microsoft.com/dynamics/2006/02/documents/MyNameSpace"

Two things, I am using XMLPAD and when I run the script it actually does just fine with the name space in there.

Unfortunately, that solution is not ideal because when I attempt to run it in another XSLT tool that I need, (at run time) it does not run correctly.

I know for a fact the namespace is throwing off the XSLT that I am using, because when I remove it from the XML, it runs fine in testing. However, this solution is not plausible because this entire process is in fact automated. So I need a solution to the namespace issue.

Anythoughts?

XPath, which is the part of XSLT you're using to match particular elements, is namespace sensitive. When you have an XPath like MyNameSpace/Table_1/Address you're matching elements without any XML namespace; namely any element Address that's a child of any element Table_1 that's a child of any element MyNameSpace that's a child of the current context node.

You need to add namespace prefixes; e.g.:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:z="http://schemas.microsoft.com/dynamics/2006/02/documents/MyNameSpace">

...

<xsl:value-of select="z:MyNameSpace/z:Table_1/z:Address"/>

Unfortunately, XSLT 1.0 does not consider the current default namespace when evaluating XPaths, so you cannot just set the default namespace and be done with it; you really need a namespace prefix.

If you can use XSLT 2.0, you could use the xpath-default-namespace attribute to set the default namespace for elements referenced in XPath queries. (XSLT 2.0 is quite a bit more practical in a lot of small ways, like this...)