Search code examples
c#xmlsoapwsdlxelement

Group XML Content By Root Name


Due to my XML creating steps (Service WSDL File Step by Step Processing) I am getting this syntax of XML:

<auth>
    <appKey>ABCD567</appKey>
</auth>
<auth>
    <appSecret>456TYUU</appSecret>
</auth>

Host Service does not accept it, responsing <one 'auth' element is missing>, it accepts this:

<auth>
    <appKey>ABCD567</appKey>
    <appSecret>456TYUU</appSecret>
</auth>

How can I achive (grouping same roots with different elements after creating XML-not possible to change creating process) this syntax by XML Handling Codes.

some part of real code is like below:

<env:Envelope
    xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
    <env:Header/>
    <soapenv:Body>
        <sch:GetCategoryAttributesRequest>
            <auth>
                <appKey>***</appKey>
                <appSecret>***</appSecret>
            </auth>
            <categoryId>1002306</categoryId>
            <pagingData>
                <currentPage>0</currentPage>
                <pageSize>100</pageSize>
            </pagingData>
            <attributeList>
                <attribute>
                    <id>354189900</id>
                </attribute>
                <attribute>
                    <mandatory>true</mandatory>
                </attribute>
            </attributeList>
        </sch:GetCategoryAttributesRequest>
    </soapenv:Body>
</soapenv:Envelope>

Solution

  • Based on the question and the last Xml add, I have supposed that the xml is like :
    NOTE : sch not exit in the posed XML, so i created it like xmlns:sch=""http://www.w3.org/2001/XMLSchema-instance""

    <env:Envelope
        xmlns:env=""http://schemas.xmlsoap.org/soap/envelope/""> 
        <env:Header/>
        <env:Body>
            <sch:GetCategoryAttributesRequest xmlns:sch=""http://www.w3.org/2001/XMLSchema-instance"">
                <auth>
                    <appKey>ABCD567</appKey>
                </auth>
                <auth>
                    <appSecret>456TYUU</appSecret>
                </auth>
                <categoryId>1002306</categoryId>
                <pagingData>
                    <currentPage>0</currentPage>
                </pagingData>
                <pagingData>
                    <pageSize>100</pageSize>
                </pagingData>
            </sch:GetCategoryAttributesRequest>
        </env:Body>
    </env:Envelope>;
    

    To get the desired output by using Linq to XML especially XDocument :

    1 - Build grouped nodes if the xml have more than one :

    var groupedItems = xDocument
                    .Descendants(xn + "GetCategoryAttributesRequest")
                    .Elements()
                    .GroupBy(x => x.Name)
                    .Select(x =>
                    {
                        return x.Skip(1).Any() ? new XElement(x.Key, x.Descendants()) : x.First();
                    }).ToList()
    

    2 - Replace the olde xml :

    xDocument.Descendants(xn + "GetCategoryAttributesRequest").First().ReplaceNodes(groupedItems);
    

    The whole code :

    string xml = @"
    <env:Envelope
        xmlns:env=""http://schemas.xmlsoap.org/soap/envelope/""> 
        <env:Header/>
        <env:Body>
            <sch:GetCategoryAttributesRequest xmlns:sch=""http://www.w3.org/2001/XMLSchema-instance"">
                <auth>
                    <appKey>ABCD567</appKey>
                </auth>
                <auth>
                    <appSecret>456TYUU</appSecret>
                </auth>
                <categoryId>1002306</categoryId>
                <pagingData>
                    <currentPage>0</currentPage>
                </pagingData>
                <pagingData>
                    <pageSize>100</pageSize>
                </pagingData>
            </sch:GetCategoryAttributesRequest>
        </env:Body>
    </env:Envelope>";
    
    XDocument xDocument = XDocument.Parse(xml);
    XNamespace xn = "http://www.w3.org/2001/XMLSchema-instance";
    
    var groupedItems = xDocument
        .Descendants(xn + "GetCategoryAttributesRequest")
        .Elements()
        .GroupBy(x => x.Name)
        .Select(x =>
        {
            return x.Skip(1).Any() ? new XElement(x.Key, x.Descendants()) : x.First();
        }).ToList();
    
    xDocument.Descendants(xn + "GetCategoryAttributesRequest").First().ReplaceNodes(groupedItems);
    
    Console.WriteLine(xDocument);
    

    Result

    <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
      <env:Header />
      <env:Body>
        <sch:GetCategoryAttributesRequest xmlns:sch="http://www.w3.org/2001/XMLSchem
    a-instance">
          <auth>
            <appKey>ABCD567</appKey>
            <appSecret>456TYUU</appSecret>
          </auth>
          <categoryId>1002306</categoryId>
          <pagingData>
            <currentPage>0</currentPage>
            <pageSize>100</pageSize>
          </pagingData>
        </sch:GetCategoryAttributesRequest>
      </env:Body>
    </env:Envelope>
        
    

    I hope you find this update helpful.