Search code examples
.netxmlxml-serializationxmldocumentxmlwriter

How can I create this XML in .Net?


I need to serialise an object to the following XML in .Net.

Probably the easiest way is to implement IXMLSerializable due to the control I need over the end result.... What do I need to do to output in the following schema:

<ns2:ProcessRepairOrder languageCode="de-DE" releaseID="1.0" systemEnvironmentCode="PROD" versionID="1.0">
    <ns2:ApplicationArea>
       <ns2:Sender>
          <ns2:CreatorNameCode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns3:TextType">SomeVendor</ns2:CreatorNameCode>
          <ns2:SenderNameCode name="Dave"/>
       <ns2:Sender>
    </ns2:ApplicationArea>
</ns2:ProcessRepairOrder>

More specifically it is the prefixes without the namespace, and the xsi:type I can't get into the XML.

the full version looks like this:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
  <S:Body>
    <ns1:PutMessage xmlns:ns1="http://www.starstandards.org/webservices/2009/transport" xmlns:ns2="http://www.starstandard.org/STAR/5" xmlns:ns3="http://www.openapplications.org/oagis/9">
      <ns1:payload>
        <ns1:content>
          <ns2:ProcessRepairOrder languageCode="de-DE" releaseID="1.0" systemEnvironmentCode="PROD" versionID="1.0">
          ...many more XML elements
      </ns2:ProcessRepairOrder>
    </ns1:PutMessage>
  </S:Body>
</S:Envelope>

Solution

  • Are you able to use .NET 3.5? If so LINQ-to-XML might be easier to use. Here is some code I've tested which will produce exactly the XML output in your question:

    XNamespace ns2 = "some-uri";
    XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
    
    XElement root = new XElement("Root",
        // Define ns2 namespace on Root element
        new XAttribute(XNamespace.Xmlns + "ns2", ns2.NamespaceName),
        new XElement(ns2 + "ProcessRepairOrder",
            // Attributes of ProcessRepairOrder
            new XAttribute("languageCode", "de-DE"),
            new XAttribute("releaseID", "1.0"),
            new XAttribute("systemEnvironmentCode", "PROD"),
            new XAttribute("versionID", "1.0"),
            // Child elements of ProcessRepairOrder
            new XElement(ns2 + "ApplicationArea",
                new XElement(ns2 + "Sender",
                    new XElement(ns2 + "CreatorNameCode",
                        // Attributes of CreatorNameCode and define xsi namespace
                        new XAttribute(XNamespace.Xmlns + "xsi", xsi.NamespaceName),
                        new XAttribute(xsi + "type", "ns3:TextType"),
                        // Value of CreatorNameCode,
                        "SomeVendor"
                    ),
                    new XElement(ns2 + "SenderNameCode",
                        // Attributes of SenderNameCode
                        new XAttribute("name", "Dave")
                    )
                )
            )
        )
    );
    

    You can look at this MSDN page to see how to create XML tress using LINQ-to-XML, and this link explains how to apply XML namespaces to them.

    Edited:

    Following on from your comments below, it seems you want a less standard approach in that you can't have the root element I've defined above, but LINQ-to-XML seems to require it in order to create a valid XML structure with the correct namespaces defined. If you want to use this approach then there is a way around it but it requires a bit more fiddling around with the output.

    Using the code I've written above and then doing root.Elements().First().ToString() would produce this serialized XML:

    <ns2:ProcessRepairOrder languageCode="de-DE" releaseID="1.0" systemEnvironmentCode="PROD" versionID="1.0" xmlns:ns2="some-uri">
      <ns2:ApplicationArea>
        <ns2:Sender>
          <ns2:CreatorNameCode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns3:TextType">SomeVendor</ns2:CreatorNameCode>
          <ns2:SenderNameCode name="Dave" />
        </ns2:Sender>
      </ns2:ApplicationArea>
    </ns2:ProcessRepairOrder>
    

    Nearly there but notice that LINQ-to-XML has inserted the xmlns:ns2 namespace on the ProcessRepairOrder because to use ns2 elements throughout the hierarchy it needs to be defined somewhere. But now that you have this in a string format you can easily use String.Replace() to remove that and you'll end up with what you require.

    I wouldn't say it is an elegant solution, but it would work for your non-standard method of producing XML.