Search code examples
c#xmlxml-deserialization

XML Deserialization with multiple elements with same name but different content


Please help me to build model for deserialization of XML with multiple tags with same name but different content.

<?xml version="1.0" encoding="utf-16"?>
<found>
<prefixes>
    <prefix name="Name1">Val1</prefix>
    <prefix name="Name2">Val2</prefix>
</prefixes>
<objects>
    <object handle="0">
        <User>
            <familyName>Family</familyName>
            <givenName>Given1</givenName>
        </User>
    </object>
    <object handle="0">
        <User>
            <familyName>Family2</familyName>
            <givenName>Given2</givenName>
        </User>
    </object>
</objects>
<objects>
    <object handle="0">
        <User>
            <familyName>Family3</familyName>
            <givenName>Given3</givenName>
        </User>
    </object>
    <object handle="0">
        <User>
            <familyName>Family4</familyName>
            <givenName>Given4</givenName>
        </User>
    </object>
</objects>

This XML contains 2 collection wrapped in tag <objects>. For debug purposes I used the same content for both <objects> tags, but in reality they'll be different. Furthermore content of each of these collection could change, but the structure of document is the same: it contains collection of prefixes, and 2 collections of objects.

Here are data objects used to serialize/deserialize this xml:

[XmlRoot(ElementName = "found", IsNullable = true)]
public class UserProfileDto
{
    [XmlArray("prefixes", Order = 0)]
    [XmlArrayItem("prefix", IsNullable = false)]
    public PrefixDto [] Prefixes { get; set; }

    [XmlArray("objects", Order = 1)]
    [XmlArrayItem(ElementName = "object", Type = typeof(ObjectDto), IsNullable = false)]
    public ObjectDto[] Objects { get; set; }

    [XmlArray("objects", Order = 2)]
    [XmlArrayItem(ElementName = "object", Type = typeof(ObjectDto), IsNullable = false)]
    public ObjectDto[] AnotherObjects { get; set; }
}

public class PrefixDto
{
    [XmlAttribute("name")]
    public string Name { get; set; }

    [XmlText]
    public string Value { get; set; }
}

public class ObjectDto
{
    [XmlElement("User")]
    public UserDto User { get; set; }
}

[Serializable]
public class UserDto
{
    [XmlElement("familyName")]
    public string FamilyName { get; set; }

    [XmlElement("givenName")]
    public string GivenName { get; set; }
}

The problem is - that serialization works fine with this model class, however when deserializing, property AnotherObjects is always null. Another strange thing - is that property Objects (in class UserProfileDto) is filled with data from the last element <object>.

Please help to deal with this deserialization.


Solution

  • I found a workaround for this problem. Before serialization xslt transformation is applied to convert xml to desired format and then resulting xml deserialized into an objects.

    For this example I applied following xslt transformation:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/found">
      <found>
        <xsl:apply-templates select="prefixes"/>
        <xsl:apply-templates select="objects[position()=1]"/>
        <xsl:apply-templates select="objects[position()=2]"/>
      </found>
    </xsl:template>
    
    <xsl:template match="prefixes">
      <prefixes>
        <xsl:copy-of select="*" />
      </prefixes>
    </xsl:template>
    
    <xsl:template match="objects[position()=1]">
      <hitObjects>
        <xsl:copy-of select="*" />
      </hitObjects>
    </xsl:template>
    
    <xsl:template match="objects[position()=2]">
      <ancillaryObjects>
         <xsl:copy-of select="*" />
      </ancillaryObjects>
    </xsl:template>
    
    </xsl:stylesheet>