Martin Felber
Martin Felber

Reputation: 121

Serialize classes to XML with namespaces

I am struggling actually with serializing my classes to the desired XML. I have problems placing the namespaces in the correct way.

here is the needed XML:

<?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://abc.def.schema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
    <q0:LoginScopeHeader>
        <organizationName>WebService Test Account</organizationName>
    </q0:LoginScopeHeader>
    <q0:SessionHeader>
        <sessionId>00f63ba748474ebba5a5ce0f8fdf7ac4</sessionId>
    </q0:SessionHeader>
</soapenv:Header>
<soapenv:Body>
    <q0:GroupSet>
        <staticGroup>
            <number>10000</number>
            <name>Gruppe A</name>
            <conference>false</conference>
            <activated>true</activated>
            <personsCounter>0</personsCounter>
            <messageName xsi:nil="true"/>
            <personNumber xsi:nil="true"/>
        </staticGroup>
        <staticGroup>
            <number>10000</number>
            <name>Gruppe A</name>
            <conference>false</conference>
            <activated>true</activated>
            <personsCounter>0</personsCounter>
            <messageName xsi:nil="true"/>
            <personNumber xsi:nil="true"/>
        </staticGroup>
    </q0:GroupSet>
</soapenv:Body>

Actually my class representation looks like this:

[XmlRoot(ElementName = "Envelope")]
public class Envelope
{
    [XmlElement(ElementName = "Header")]
    public Header Header { get; set; }
    [XmlElement(ElementName = "Body")]
    public Body Body { get; set; }
    [XmlAttribute(AttributeName = "soapenv")]
    public string Soapenv { get; set; }
    [XmlAttribute(AttributeName = "q0")]
    public string Q0 { get; set; }
    [XmlAttribute(AttributeName = "xsd")]
    public string Xsd { get; set; }
    [XmlAttribute(AttributeName = "xsi")]
    public string Xsi { get; set; }
}

[XmlRoot(ElementName = "LoginScopeHeader")]
public class LoginScopeHeader
{
    [XmlElement(ElementName = "organizationName")]
    public string OrganizationName { get; set; }
}

[XmlRoot(ElementName = "SessionHeader")]
public class SessionHeader
{
    [XmlElement(ElementName = "sessionId")]
    public string SessionId { get; set; }
}

[XmlRoot(ElementName = "Header")]
public class Header
{
    [XmlElement(ElementName = "LoginScopeHeader")]
    public LoginScopeHeader LoginScopeHeader { get; set; }
    [XmlElement(ElementName = "SessionHeader")]
    public SessionHeader SessionHeader { get; set; }
}

[XmlRoot(ElementName = "Body")]
public class Body
{
    [XmlElement(ElementName = "GroupSet")]
    public GroupSet GroupSet { get; set; }
}

[XmlRoot(ElementName = "GroupSet")]
public class GroupSet
{
    [XmlElement(ElementName = "staticGroup")]
    public List<StaticGroup> StaticGroup { get; set; }
}

[XmlRoot(ElementName = "staticGroup")]
public class StaticGroup
{
    [XmlElement(ElementName = "number")]
    public string Number { get; set; }
    [XmlElement(ElementName = "name")]
    public string Name { get; set; }
    [XmlElement(ElementName = "conference")]
    public string Conference { get; set; }
    [XmlElement(ElementName = "activated")]
    public string Activated { get; set; }
    [XmlElement(ElementName = "personsCounter")]
    public string PersonsCounter { get; set; }
    [XmlElement(ElementName = "messageName")]
    public MessageName MessageName { get; set; }
    [XmlElement(ElementName = "personNumber")]
    public PersonNumber PersonNumber { get; set; }
}

[XmlRoot(ElementName = "messageName")]
public class MessageName
{
    [XmlAttribute(AttributeName = "nil")]
    public string Nil { get; set; }
}

[XmlRoot(ElementName = "personNumber")]
public class PersonNumber
{
    [XmlAttribute(AttributeName = "nil")]
    public string Nil { get; set; }
}

And here the extension method for the serialization:

public static string XmlSerialize<T>(this T item, bool removeNamespaces = true)
    {
        object locker = new object();

        XmlSerializerNamespaces xmlns = new XmlSerializerNamespaces();
        xmlns.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
        xmlns.Add("xsd", "http://www.w3.org/2001/XMLSchema");
        xmlns.Add("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");

        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));

        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true;
        settings.OmitXmlDeclaration = true;

        lock (locker)
        {
            StringBuilder stringBuilder = new StringBuilder();
            using (StringWriter stringWriter = new StringWriter(stringBuilder))
            {
                using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, settings))
                {
                    if (removeNamespaces)
                    {
                        xmlSerializer.Serialize(xmlWriter, item, xmlns);
                    }
                    else { xmlSerializer.Serialize(xmlWriter, item); }

                    return stringBuilder.ToString();
                }
            }
        }
    }

I have actually no clue how the get the namespaces serialized like in the above XML.

What do I miss? Any help is highly appreciated

Upvotes: 0

Views: 1441

Answers (2)

steve16351
steve16351

Reputation: 5812

You need to assign your serialisation attributes with the appropriate namespaces. The Envelope, Body and Header elements have the namespace http://schemas.xmlsoap.org/soap/envelope/. So your Envelope class should look like this:

[XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Envelope
{
    [XmlElement(ElementName = "Header")]
    public Header Header { get; set; }
    [XmlElement(ElementName = "Body")]
    public Body Body { get; set; }
}

You have added the namespace prefixes (q0, xsi, xsd) as properties of your Envelope class, this is not necessary so you can remove them.

The other namespace involved is http://abc.def.schema which has the q0 prefix. You should assign that where needed at the top level, for example, in the Body class, it should be assigned to the GroupSet property:

[XmlRoot(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Body
{
    [XmlElement(ElementName = "GroupSet", Namespace = "http://abc.def.schema")]
    public GroupSet GroupSet { get; set; }
}

When you come to serialize, at the moment you are not telling the serializer about the q0 namespace prefix. So you need to add this in your XmlSerialize<T> extension method:

xmlns.Add("q0", "http://abc.def.schema");

Your StaticGroup element does not have a namespace defined in your example XML. So your GroupSet needs to define an empty namespace here:

[XmlRoot(ElementName = "GroupSet", Namespace = "http://abc.def.schema")]
public class GroupSet
{
    [XmlElement(ElementName = "staticGroup", Namespace = "")]
    public List<StaticGroup> StaticGroup { get; set; }
}

Upvotes: 1

Martin Felber
Martin Felber

Reputation: 121

UPDATE_1:

I have added the namespaces as suggested by jdweng like so:

[XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Envelope
{
    [XmlElement(ElementName = "Header")]
    public Header Header { get; set; }
    [XmlElement(ElementName = "Body")]
    public Body Body { get; set; }
    [XmlAttribute(AttributeName = "soapenv")]
    public string Soapenv { get; set; }
    [XmlAttribute(AttributeName = "q0")]
    public string Q0 { get; set; }
    [XmlAttribute(AttributeName = "xsd")]
    public string Xsd { get; set; }
    [XmlAttribute(AttributeName = "xsi")]
    public string Xsi { get; set; }
}

[XmlRoot(ElementName = "Header", Namespace = http://schemas.xmlsoap.org/soap/envelope/")]
public class Header
{
    [XmlElement(ElementName = "LoginScopeHeader")]
    public LoginScopeHeader LoginScopeHeader { get; set; }
    [XmlElement(ElementName = "SessionHeader")]
    public SessionHeader SessionHeader { get; set; }
}

[XmlRoot(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Body
{
    [XmlElement(ElementName = "PersonSet")]
    public PersonSet PersonSet { get; set; }
}

but now I get the following XML:

<soapenv:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <soapenv:LoginScopeHeader>
      <soapenv:organizationName>Blablabla</soapenv:organizationName>
    </soapenv:LoginScopeHeader>
    <soapenv:SessionHeader>
      <soapenv:sessionId>654654654654654654654</soapenv:sessionId>
    </soapenv:SessionHeader>
  </soapenv:Header>
  <soapenv:Body>
    <soapenv:PersonSet>
      <soapenv:elements>
        <soapenv:active>true</soapenv:active>
        <soapenv:number>321321321</soapenv:number>
        <soapenv:name1>John</soapenv:name1>
        <soapenv:name2>Doe</soapenv:name2>
        <soapenv:language>DE</soapenv:language>
        <soapenv:extra />
        <soapenv:remarks>remarks</soapenv:remarks>
        <soapenv:pin>65454</soapenv:pin>
        <soapenv:onDutyManagement>false</soapenv:onDutyManagement>
        <soapenv:onDutyManagementAutomaticLogoutDuration>0</soapenv:onDutyManagementAutomaticLogoutDuration>
        <soapenv:onDutyManagementNotification>false</soapenv:onDutyManagementNotification>
        <soapenv:contactDataManager>false</soapenv:contactDataManager>
        <soapenv:contactDataManagedBy nil="1" />
        <soapenv:caseManagerAccessMode>NO_ACCESS</soapenv:caseManagerAccessMode>
        <soapenv:plannedPeriodsOfAbsence nil="1" />
        <soapenv:groups>
          <soapenv:elements>
            <soapenv:active>true</soapenv:active>
            <soapenv:conference_moderator>false</soapenv:conference_moderator>
            <soapenv:time_offset>0</soapenv:time_offset>
            <soapenv:groupNumber>123456</soapenv:groupNumber>
          </soapenv:elements>
        </soapenv:groups>
        <soapenv:devices>
          <soapenv:elements>
            <soapenv:callingNumberOrEmail>[email protected]</soapenv:callingNumberOrEmail>
            <soapenv:prio_working_hours>1</soapenv:prio_working_hours>
            <soapenv:prio_non_working_hours>0</soapenv:prio_non_working_hours>
            <soapenv:dtmfExtensionNumber />
            <soapenv:deviceName>EMail Privat</soapenv:deviceName>
          </soapenv:elements>
        </soapenv:devices>
      </soapenv:elements>
    </soapenv:PersonSet>
  </soapenv:Body>
</soapenv:Envelope>

Upvotes: 0

Related Questions