Search code examples
c#xmlxslt

C# Remove namespace references and usage from XML data


I'm obtaining Swift MX messages and need to remove namespaces from them. In essence, they are two XML documents glued together. Most of the time they look like this:

<AppHdr> contents of the header </AppHdr><Document> contents of the document </Document>

This is easy to deal with as I put <root> and </root> around the whole thing to make XML (one root node only) and read it into an XmlDocument:

<root><AppHdr> ... </AppHdr><Document> ... </Document></root>

However, some of the messages have namespaces and the namespace is unknown at designtime. An example might be:

<ns2:AppHdr xmlns:ns2="some stuff"> contents of the header </ns2:AppHdr><ns3:Document xmlns:ns3="some other stuff"> contents of the document </ns3:Document>

Note that all of the XML tree under AppHdr quote the namespace tag of AppHdr and those under Document quote that of Document.

The namespace tags may vary. In this example they are ns2 and ns3, but I don't know what they will be in advance. Is there an easy way to strip these out?


Solution

  • A minimal reproducible example is not provided. Here is a generic XSLT based solution that will work with any well-formed XML file.

    Input XML

    <root>
       <ns2:AppHdr xmlns:ns2="some stuff">*contents of the header*</ns2:AppHdr>
       <ns3:Document xmlns:ns3="some other stuff">*contents of the document*</ns3:Document>
    </root>
    

    XSLT

    <?xml version='1.0'?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
       <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
       <xsl:strip-space elements="*"/>
    
       <!-- template to copy elements -->
       <xsl:template match="*">
          <xsl:element name="{local-name()}">
             <xsl:apply-templates select="@* | node()"/>
          </xsl:element>
       </xsl:template>
    
       <!-- template to copy attributes -->
       <xsl:template match="@*">
          <xsl:attribute name="{local-name()}">
             <xsl:value-of select="."/>
          </xsl:attribute>
       </xsl:template>
    
       <!-- template to copy the rest of the nodes -->
       <xsl:template match="comment() | text() | processing-instruction()">
          <xsl:copy/>
       </xsl:template>
    </xsl:stylesheet>
    

    Output XML

    <root>
      <AppHdr>*contents of the header*</AppHdr>
      <Document>*contents of the document*</Document>
    </root>
    

    c#

    void Main()
    {
       const string SOURCEXMLFILE = @"e:\Temp\input.xml";
       const string XSLTFILE = @"e:\Temp\process.xslt";
       const string OUTPUTXMLFILE = @"e:\temp\output.xml";
    
       try
       {
          XsltArgumentList xslArg = new XsltArgumentList();
    
          using (XmlReader src = XmlReader.Create(SOURCEXMLFILE))
          {
             XslCompiledTransform xslt = new XslCompiledTransform();
             xslt.Load(XSLTFILE, new XsltSettings(true, true), new XmlUrlResolver());
    
             XmlWriterSettings settings = xslt.OutputSettings.Clone();
             settings.IndentChars = "\t";
             // to remove BOM
             settings.Encoding = new UTF8Encoding(false);
    
             using (XmlWriter result = XmlWriter.Create(OUTPUTXMLFILE, settings))
             {
                xslt.Transform(src, xslArg, result, new XmlUrlResolver());
                result.Close();
             }
          }
          Console.WriteLine("File '{0}' has been generated.", OUTPUTXMLFILE);
       }
       catch (Exception ex)
       {
          Console.WriteLine(ex.Message);
       }
    }