简体   繁体   中英

How to remove 2 parent namespace tags from XML document

I have the following XML document, but I need to remove the first two elements (and keep all the children). I can't seem to do this using XPath because they are namespaces? I don't really understand this part of an XML document so any explanations would also be very welcome. Also the HubChangeRequest is variable so I can't use that in the code - I need to basically remove the 2 parent elements.

<?xml version="1.0" encoding="UTF-8" standalone="no" ?> 
<mgns1:PlaceXmlMessage xmlns:mgns1="http://www.testing.com/">
    <mgns1:xmlDocument>
        <HubChangeRequest version="1.0">
            <TransactionReference>
                <AuthenticationID>TestSUPPLIERS</AuthenticationID>
                <AuthenticationKey>hidden</AuthenticationKey>
                <TransactionNumber>hidden</TransactionNumber>
            </TransactionReference>
            <MessageNumber>hidden</MessageNumber>
            <MessageCreatedDate>2016-03-01T12:31:31</MessageCreatedDate>
            <ReferenceNumber>ABC123456789</ReferenceNumber>
            <ProductDetails>
                <StockItem LineReference="123456/1">
                    <NewStatus>Despatched</NewStatus>
                    <DespatchReference>3 PARCEL LINE</DespatchReference>
                </StockItem>
                <StockItem LineReference="123345/2">
                    <NewStatus>Despatched</NewStatus>
                    <DespatchReference>3 PARCEL LINE</DespatchReference>
                </StockItem>
            </ProductDetails>
        </HubChangeRequest>
    </mgns1:xmlDocument>
</mgns1:PlaceXmlMessage>

To be clear this is what I wanted to end up with:

<?xml version="1.0" encoding="UTF-8" standalone="no" ?> 
<HubChangeRequest version="1.0">
    <TransactionReference>
        <AuthenticationID>TestSUPPLIERS</AuthenticationID>
        <AuthenticationKey>hidden</AuthenticationKey>
        <TransactionNumber>hidden</TransactionNumber>
    </TransactionReference>
    <MessageNumber>hidden</MessageNumber>
    <MessageCreatedDate>2016-03-01T12:31:31</MessageCreatedDate>
    <ReferenceNumber>ABC123456789</ReferenceNumber>
    <ProductDetails>
        <StockItem LineReference="123456/1">
            <NewStatus>Despatched</NewStatus>
            <DespatchReference>3 PARCEL LINE</DespatchReference>
        </StockItem>
        <StockItem LineReference="123345/2">
            <NewStatus>Despatched</NewStatus>
            <DespatchReference>3 PARCEL LINE</DespatchReference>
        </StockItem>
    </ProductDetails>
</HubChangeRequest>

Try this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string xml =
                "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>" +
                "<mgns1:PlaceXmlMessage xmlns:mgns1=\"http://www.testing.com/\">" +
                    "<mgns1:xmlDocument>" +
                        "<HubChangeRequest version=\"1.0\">" +
                            "<TransactionReference>" +
                                "<AuthenticationID>TestSUPPLIERS</AuthenticationID>" +
                                "<AuthenticationKey>hidden</AuthenticationKey>" +
                                "<TransactionNumber>hidden</TransactionNumber>" +
                            "</TransactionReference>" +
                            "<MessageNumber>hidden</MessageNumber>" +
                            "<MessageCreatedDate>2016-03-01T12:31:31</MessageCreatedDate>" +
                            "<ReferenceNumber>ABC123456789</ReferenceNumber>" +
                            "<ProductDetails>" +
                                "<StockItem LineReference=\"123456/1\">" +
                                    "<NewStatus>Despatched</NewStatus>" +
                                    "<DespatchReference>3 PARCEL LINE</DespatchReference>" +
                                "</StockItem>" +
                                "<StockItem LineReference=\"123345/2\">" +
                                    "<NewStatus>Despatched</NewStatus>" +
                                    "<DespatchReference>3 PARCEL LINE</DespatchReference>" +
                                "</StockItem>" +
                            "</ProductDetails>" +
                        "</HubChangeRequest>" +
                    "</mgns1:xmlDocument>" +
                "</mgns1:PlaceXmlMessage>";

            XDocument doc = XDocument.Parse(xml);

            XElement placeXmlMessage = (XElement)doc.FirstNode;
            XElement secondNode = placeXmlMessage.Elements().FirstOrDefault();
            XElement hubChangeRequest = secondNode.Elements().FirstOrDefault();
            placeXmlMessage.ReplaceWith(hubChangeRequest);
        }
    }
}

You can use an XSLT transformation to get your input into the right output shape.

The following code transforms your input xml, assuming it lives in a string variable caled input , to an MemoryStream.

Transform input via XSLT to stream

// Create an XSLT Transformer
var xslt = new XslCompiledTransform();
xslt.Load("copydoc.xslt");

var settings = new XmlWriterSettings
{
    Encoding = new UTF8Encoding(false) // NO BOM
};

// open all streams for reading and writing
using (var ms = new MemoryStream())
{
    using (var xw = XmlWriter.Create(ms, settings))
    {
        // input is the string with the xml input
        using (var sr = new StringReader(input))
        using (var xr = XmlReader.Create(sr))
        {
            xslt.Transform(xr, xw);
            // the memorystream now has the result
        }
    }

    Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
}

Copydoc.xslt

The Xslt file is fairly simple and uses two templates and a strategic apply-template to get the childnode under your <mgsn1:xmlDocument> node:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
                xmlns:mgns1="http://www.testing.com/"
                exclude-result-prefixes="msxsl mgns1 "
>
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
      <!-- select the child node of xmlDocument-->
      <xsl:apply-templates select="mgns1:PlaceXmlMessage/mgns1:xmlDocument/child::*" />
    </xsl:template>

    <!-- match each element -->
    <xsl:template match="*">
      <!-- make sure to get rid of the namespaces-->
        <xsl:element name="{local-name(.)}">
        <!-- be explicit about copying attributes -->
        <xsl:apply-templates select="@*" />
        <!-- copy childs-->
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

    <!-- handle attributes -->
    <xsl:template match="@*">
        <xsl:copy/>
    </xsl:template>

</xsl:stylesheet>

If you add the file copydoc.xslt to your project don't forget to set the projectfile property Copy to output directory to copy always otherwise the xslt file will not be found.

Thanks for your help, I managed to solve this with

 xmlDOM.LoadXml(p_strXmlDocument);
 XmlElement root = xmlDOM.DocumentElement;

 XmlNamespaceManager NameSpaceManager = new XmlNamespaceManager(new NameTable());
 NameSpaceManager.AddNamespace("mgns1", "http://www.hidden.com/");

 XmlNodeList nodeList = xmlDOM.SelectNodes("//mgns1:xmlDocument/*", NameSpaceManager);
 string returnStr = "";
 if (nodeList != null)
 {
      foreach (XmlNode node in nodeList)
      {
            returnStr += node.OuterXml;
      }
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM