XML Namespace is throwing off my XSLT

2019-08-07 17:34发布

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?

2条回答
你好瞎i
2楼-- · 2019-08-07 18:06

You could use a generic match for elements and a predicate filter on the local-name()

e.g. *[local-name()='MyNameSpace']/*[local-name()='Table_1']/*[local-name()='Address']

WARNING: This is a more generic match, so you could get unpredictable results if you have a document with different namespace qualified elements with the same name.

查看更多
Luminary・发光体
3楼-- · 2019-08-07 18:13

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...)

查看更多
登录 后发表回答