Search code examples
c#.netxmlxelement

How can I remove an unwanted node from a list of XElements?


I need to use C# to manicure the response from a service before handing it off to the caller. The service takes a series of requests in XML format, formats the message and send it to the service. The response looks similar to this:

<SvcRes>
    <SvcVer>1.0</SvcVer>
    <MsgUUID>12345678-1234-1234-1234-123456789012</MsgUUID>
    <Svc>
        <SvcParms>
            <ApplID>App</ApplID>
            <SvcID>AppSrch</SvcID>
            <SvcVer>1.0</SvcVer>
        </SvcParms>
        <MsgData>
            <AppResData>
                <Key>xxxxxxxx</Key>
                <Rslt>xxxxxxxx</Rslt>
                <ErrCde>0</ErrCde>
                <ApplMsgLst>
                    <ApplMsg>
                        <ApplMsgApplId>D6</ApplMsgApplId>
                        <ApplMsgNbr>0</ApplMsgNbr>
                        <ApplMsgTxt>INQUIRY COMPLETE     09:23:53</ApplMsgTxt>
                        <ApplMsgErrInd>N</ApplMsgErrInd>
                    </ApplMsg>
                </ApplMsgLst>
            </AppResData>
        </MsgData>
        <ErrCde>0</ErrCde>
        <ErrMsg/>
    </Svc>
    <Svc>
        <SvcParms>
            <ApplID>DP</ApplID>
            <SvcID>DPKywrd</SvcID>
            <SvcVer>1.0</SvcVer>
            <RqstUUID>12345678-1234-1234-1234-123456789012</RqstUUID>
        </SvcParms>
        <MsgData>
            <AppResData>
                <Key>xxxxxxxx</Key>
                <Rslt>xxxxxxxx</Rslt>
                <ErrCde>0</ErrCde>
                <ApplMsgLst>
                    <ApplMsg>
                        <ApplMsgApplId>D6</ApplMsgApplId>
                        <ApplMsgNbr>0</ApplMsgNbr>
                        <ApplMsgTxt>INQUIRY COMPLETE     09:23:53</ApplMsgTxt>
                        <ApplMsgErrInd>N</ApplMsgErrInd>
                    </ApplMsg>
                </ApplMsgLst>
            </AppResData>
        </MsgData>
        <ErrCde>0</ErrCde>
        <ErrMsg/>
      <Svc>
    <ErrCde>0</ErrCde>
    <ErrMsg>Success</ErrMsg>
</SvcRes>

I need to pull out the AppResData nodes, then strip out the ApplMsgLst nodes from each of them before sending the results back to the caller. The resulting XML should be like this:

<AppResData>
    <Key>xxxxxxxx</Key>
    <Rslt>xxxxxxxx</Rslt>
    <ErrCde>0</ErrCde>
</AppResData>
<AppResData>
    <Key>xxxxxxxx</Key>
    <Rslt>xxxxxxxx</Rslt>
    <ErrCde>0</ErrCde>
</AppResData>

I can get a list of XElement nodes using the following 2 lines of code:

var xml = XElement.Parse(xmlResponse);
var msgData = xml.DescendantsAndSelf("MsgData");
  • then I can do string.Concat(msgData.Nodes()) to get the final string to return to the caller -- BUT at this point I don't know how to delete the inner ApplMsgLst nodes. I have tried converting it back to a string and reparsing, but of course it complains about multiple root elements. I have tried every Remove combination I can think of, but they always remove too much (everything) or nothing..

Is there another way to do this? There is no file, this is all string data in a SOAP web service.


Solution

  • Here is an XSLT based solution.

    Parameters:

    • Input XML as a string data type.
    • XSLT as a file.
    • Output XML as a string data type.

    XSLT

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output indent="yes" omit-xml-declaration="yes"/>
    
        <xsl:template match="/SvcRes">
            <root>
                <xsl:for-each select="Svc/MsgData/AppResData">
                    <xsl:copy>
                        <xsl:copy-of select="Key"/>
                        <xsl:copy-of select="Rslt"/>
                        <xsl:copy-of select="ErrCde"/>
                    </xsl:copy>
                </xsl:for-each>
            </root>
        </xsl:template>
    </xsl:stylesheet>
    

    c#

    void Main()
    {
        const string XSLTFILE = @"e:\Temp\DaveN59.xslt";
        string inputXML = @"<SvcRes>
            ...
        </SvcRes>";
    
        try
        {
            StringReader rdr = new StringReader(inputXML);
            XPathDocument XPathDoc = new XPathDocument(rdr);
    
            XslCompiledTransform xslt = new XslCompiledTransform();
            xslt.Load(XSLTFILE);
    
            StringWriter sw = new StringWriter();
            using (XmlWriter xwo = XmlWriter.Create(sw, xslt.OutputSettings))
            {
                xslt.Transform(XPathDoc, xwo);
            }
            
            Console.WriteLine(sw.ToString());
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
    

    Output XML

    <root>
      <AppResData>
        <Key>xxxxxxxx</Key>
        <Rslt>xxxxxxxx</Rslt>
        <ErrCde>0</ErrCde>
      </AppResData>
      <AppResData>
        <Key>xxxxxxxx</Key>
        <Rslt>xxxxxxxx</Rslt>
        <ErrCde>0</ErrCde>
      </AppResData>
    </root>