Search code examples
c#xmlxml-serialization

XML deserialize to same object different element names


I am trying to deserialize an xml to an object to use. We have created templates and would like to keep the xml the same standard if possible. The problem I am trying to figure out is how to look within a standard node in the xml and all subnodes are the same object type, just with different node names.

For example:

<Account>
    <AccountNumber>12345</AccountNumber>
    <Balance>12.52</Balance>
    <LateFee>0</LateFee>
</Account>

The Account level is always within the template, but everything below that is variable. Is there a way to deserialize all nodes within the Account level to be the same object?

Public Class AccountNode
{
   Public String Name { get; set; }
   Public String Value { get; set; }
}

Based on my research, it appears, they have to have a standard naming schema and then you can have an attribute to assign to the Name value. I just haven't been able to confirm that. If someone has a link that I haven't been able to find, or is knowledgeable and can confirm whether or not this is a possibility, I would like to know.

EDIT:

I have a much larger xml than listed above, so I'm trying to see how I can deserialize it.

<AccountNumber>
  <KeyWord Name="Customer Account" isRegex="False" errorAllowance="10" LookFor="Customer Account">
    <Rectangle>
      <Left>200</Left>
      <Bottom>350</Bottom>
      <Right>600</Right>
      <Top>690</Top>
    </Rectangle>
    <Relations KwName="Charges">
      <Relation>above.0</Relation>
    </Relations>
  </KeyWord>
  <Capture DataType="String" FindIfKeywordMissing="false">
    <Rectangle>
      <Left>200</Left>
      <Bottom>350</Bottom>
      <Right>600</Right>
      <Top>690</Top>
    </Rectangle>
    <Relations anchorName="ChargeSection">
      <Relation>rightOf.0</Relation>
      <Relation>below.-20</Relation>
      <Relation>above.20</Relation>
      <Relation>width.150</Relation>
    </Relations>
    <Regex>Customer account\s+(\S+)</Regex>
  </Capture>
</AccountNumber>

So with this one, I assume it is similar, but basically the Account Number node is the variable one and everything above and below it is standard.


Solution

  • You could use a surrogate [XmlAnyElement] public XElement[] AccountNodesXml property in your Account class to manually convert your AccountNode objects from and to XML nodes. Marking the property with XmlAnyElement ensures that the elements will taken verbatim from the XML:

    public class Account
    {
        public Account() { this.AccountNodes = new List<AccountNode>(); }
    
        [XmlIgnore]
        public List<AccountNode> AccountNodes { get; set; }
    
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAnyElement]
        public XElement[] AccountNodesXml
        {
            get
            {
                if (AccountNodes == null)
                    return null;
                return AccountNodes.Select(a => new XElement((XName)a.Name, a.Value)).ToArray();
            }
            set
            {
                if (value != null)
                    AccountNodes = value.Select(e => new AccountNode { Name = e.Name.LocalName, Value = (string)e }).ToList();
            }
        }
    }
    

    Sample fiddle which successfully deserialized and re-serializes the following XML:

    <Account>
      <AccountNumber>12345</AccountNumber>
      <Balance>12.52</Balance>
      <LateFee>0</LateFee>
    </Account>