2

I have two XML objects that I believe describe the same entity, one uses namespace prefixes, and one uses inline namespace declarations. I want to diff them, but the different ways of representing the namespace make that all but impossible.

How can I take the first xml snippet below and change it to match the second snippet?

<!--I want to take data that looks like this-->
<Foo xmlns:e="http://schemas.cch.com/FooBar/MDS/2007/12/04/Foo">
  <e:Description></e:Description>
  <e:Name i:nil="true"></e:Name>
  <e:DisplaySeqNo>0</e:DisplaySeqNo>
</Foo>

<!--I want to make that data that looks like this-->
<Foo>
  <Description xmlns="http://schemas.cch.com/FooBar/MDS/2007/12/04/Foo"></Description>
  <Name i:nil="true" xmlns="http://schemas.cch.com/FooBar/MDS/2007/12/04/Foo"></Name>
  <DisplaySeqNo xmlns="http://schemas.cch.com/FooBar/MDS/2007/12/04/Foo">0</DisplaySeqNo>
</Foo>

The requirement to diff them is part of a manual debugging process process, so I'd be happy with a web tool, script, or whatever. I don't plan on doing this regularly but am ripping my hair out trying to figure out how xml sample A is different than xml sample B.

Sidney
  • 624
  • 7
  • 20
  • Are you OKI with using XSLT-1.0? – zx485 Feb 06 '20 at 21:56
  • Preferred languages or technologies for a non-XSLT solution? –  Feb 06 '20 at 21:58
  • @Amy I've never used XSLT, so I don't know if I'm ok with it or not, but if a snippet can get me from A to B I'd be more than happy to use it. – Sidney Feb 06 '20 at 21:59
  • My current thinking is you could start with and adapt [this code](https://stackoverflow.com/questions/5268182/how-to-remove-namespaces-from-xml-using-xslt), except instead of removing, you replace. I think `localname()` would need to become `name()`. *I think*. My knowledge of XSLT is rather limited. –  Feb 06 '20 at 22:02

1 Answers1

2

You can use the following XSLT-1.0 stylesheet. It's a combination of the Identity template (which copies all nodes) with two templates handling the replacement situation:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:e="http://schemas.cch.com/FooBar/MDS/2007/12/04/Foo">
    <xsl:output method="xml" indent="yes"/>

    <!-- Identity template -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Foo">
      <xsl:element name="{local-name()}" namespace="">
        <xsl:apply-templates select="node()|@*" />
      </xsl:element>
    </xsl:template>

    <xsl:template match="e:*">
      <xsl:element name="{local-name()}" namespace="http://schemas.cch.com/FooBar/MDS/2007/12/04/Foo">
        <xsl:apply-templates select="node()|@*" />
      </xsl:element>
    </xsl:template>    

</xsl:stylesheet>

Its output is:

<Foo>
  <Description xmlns="http://schemas.cch.com/FooBar/MDS/2007/12/04/Foo"/>
  <Name xmlns="http://schemas.cch.com/FooBar/MDS/2007/12/04/Foo" i:nil="true"/>
  <DisplaySeqNo xmlns="http://schemas.cch.com/FooBar/MDS/2007/12/04/Foo">0</DisplaySeqNo>
</Foo>

It also produces an error for the XML file, because the i namespace is not defined in it. It also copies the comment from the input XML, but I guess that was just a comment for illustration and can therefore be ignored.

If you're using some kind of Linux, you can easily pass this template to xsltproc.

zx485
  • 28,498
  • 28
  • 50
  • 59
  • Just an FYI, in windows this can be done by having an xml file, adding a xslt file to the xml file's stylesheet property, then choosing to start xslt (with or without debugging) from visual studio. (Also, thank you!) – Sidney Feb 06 '20 at 22:17