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?
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.
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 elementAddress
that's a child of any elementTable_1
that's a child of any elementMyNameSpace
that's a child of the current context node.You need to add namespace prefixes; e.g.:
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...)