2

I'm trying to write a generic method that can be used to deserialize xml to an array of objects.

Given XML that looks like so:

<people>
    <person>
        <someElement>content</someElement>
    </person>
    <person>
        <someElement>more content</someElement>
    </person>
</people>

Shown in the below code as xmlDoc. And a person class as T

XmlNodeReader reader = new XmlNodeReader(xmlDoc.DocumentElement);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T[]), new XmlRootAttribute(xmlDoc.DocumentElement.Name));
results = xmlSerializer.Deserialize(reader) as T[];

This works as expected, and returns person[] with 2 entries.

However, in the API I am working with, if there is only 1 result returned, it just returns:

<person>
    <someElement>content</someElement>
</person>

And my deserialization breaks down. person[] remains empty.

Any thoughts on the best way to implement this?

Edit

I'm contemplating running an XSLT in between, and passing the name of T in, if it matches the root node, then add a wrapping node?

1
  • You mean there's no people root node in this case? Commented Jun 21, 2010 at 9:01

2 Answers 2

1

I ended up using XSLT to ensure the node(s) I was after weren't the root.

Basically I've a XSLT file containing:

<xsl:template match="/">
    <rootNode>
        <xsl:apply-templates select="node()|@*"/>
    </rootNode>
</xsl:template>

(Not sure if this XSLT is ideal, would love some comments).

This wraps a around my inbound XML from the api. My previously mentioned Person class has a [XmlType("person")] attribute applied to it, armed with that I can do:

//using reflection to look what the XmlType has been declared on this type
var typeAttributes = Attribute.GetCustomAttribute(typeof(T), typeof(XmlTypeAttribute));

//determine an xpath query to find this type of elements parent
string xPathtoTypeName = string.Format("//{0}/parent::node()", ((XmlTypeAttribute)typeAttributes).TypeName);

//use the above xpath query to find the parent node.
var parentNode = transformedDocument.SelectSingleNode(xPathtoTypeName);

//deserialize as before
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T[]), new XmlRootAttribute(parentNode.Name));
XmlNodeReader nodeReader = new XmlNodeReader(parentNode);
results = xmlSerializer.Deserialize(nodeReader) as T[];
Sign up to request clarification or add additional context in comments.

Comments

0

Check Name of the Root element, and if it is not people, add it to xml, and everything will go fine.


Update: Check deep of the xml document, and if its == 2, create root element. Another way - use of LINQ-TO-XML XElement.Descandants("person") - array of person-elements

2 Comments

Need a way to handle this generically. The posted sample is just an example, there is >100 different xml types.
Can't check for depth, as the real data could be a number of depths, also checking for a specific node using L2Xml wouldn't be generic.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.