I am deserializing a large xml doc into a C# object.
I've run into an issue where there are multiple xml elements on the same line, and am having trouble re-constructing them properly in code.
A snippet example as so:
<parent>
<ce:para view="all">
Text <ce:cross-ref refid="123">[1]</ce:cross-ref> More Text <ce:italic>Italicized text</ce:italic> and more text here
</ce:para>
<ce:para>...</ce:para>
</parent>
The generated C# class looks like this
[XmlRoot(ElementName = "para", Namespace = "namespace")]
public class Para
{
[XmlElement(ElementName = "cross-ref", Namespace = "namespace")]
public List<Crossref> Crossref { get; set; }
[XmlText]
public List<string> Text { get; set; }
[XmlElement(ElementName = "italic", Namespace = "namespace")]
public List<Italic> Italic { get; set; }
}
I want to be able to loop over this object and re-construct the sentence as a plain string.
Text [1] More Text Italicized Text and more text here
The only problem is though when the deserialization happens, the order is lost as each bit is stuck into it's respective object. This means I have no way of knowing how to reconstruct the string back to how it is supposed to be.
Text: {"Text", "More Text", "and more text here"}
Crossref: {"[1]"}
Italic: {"Italicized Text"}
I've thought about bringing in the whole element in as a string, and then scrubbing the tags out of it, but I'm not sure how to properly get it deserialized. Or if there is a better way to go about it.
Disclaimer: I am not able to alter the XML document as it is coming in from a 3rd party.
Thanks
Once you have deserialized the 3rd party XML into an object that directly matches the XML's schema (as you have done already in your example above) you should be able to use XmlNode.InnerText() on the <ce:para node to extract what you're looking for without having to write any parsing code.
At that point, you could do a translation from the object you deserialized into from the raw 3rd party XML into an object which flattens out the <ce:para node into a simple string.
As per Chris' request, I'm posting my solution. It probably could used refining as I'm not very experienced with linq queries.
XDocument xdoc = xmlAdapter.GetAsXDoc(xmlstring);
IEnumerable<XElement> body = from b in xdoc.Descendants()
where b.Name.LocalName == "body"
select b;
IEnumerable<XElement> sections = from s in body.Descendants()
where s.Name.LocalName == "sections"
select s;
IEnumerable<XElement> paragraphs = from p in sections.Descendants()
where p.Name.LocalName == "para"
select p;
string bodytext = "";
if (paragraphs.Count() > 0)
{
StringBuilder text = new StringBuilder();
foreach (XElement p in paragraphs)
{
text.AppendFormat("{0} ", p.Value);
}
}
bodytext = text.ToString();
Related
As per title am having issues getting data from an XML file with CDATA elements into an array.
Based on my current limited understanding of how to do it, I came up with this basic working method
CDATA is odd so my normal methods didn't work. My normal route of finding the nodes wasn't stopping on them, and then there is the whole CDATA issue.
XmlTextReader xmlReader = new XmlTextReader(FilePath);
while (xmlReader.Read())
{
// Position the reader on the OrderNumber node
xmlReader.ReadToFollowing("quoteNumber");
XmlReader inner = xmlReader.ReadSubtree();
while (inner.Read())
{
switch (xmlReader.NodeType)
{
case XmlNodeType.CDATA:
Globals.COData[0] = inner.Value;
break;
}
}
xmlReader.ReadToFollowing("orderNumber");
inner = xmlReader.ReadSubtree();
while (inner.Read())
{
switch (xmlReader.NodeType)
{
case XmlNodeType.CDATA:
Globals.COData[1] = inner.Value;
break;
}
}
But I have many many data elements to fetch and assume there is a better way. File looks like:
And the relevant portion:
<quoteNumber>
<![CDATA[ John Test 123]]>
</quoteNumber>
<orderNumber>
<![CDATA[ 1352738]]>
</orderNumber>
The item contained does have a closing element at file end. The entire XML is too large to post.
the XML format is not in my control.
My end goal is to get the OrderNumber and its value into an array. And the Quote number and its value. I am used to seeing <OrderNumber>123</OrderNumber> so CDATA nodes are new to me.
It's not entirely clear where you are going wrong because you don't share your complete XML, but you are not checking the return value from XmlReader.ReadToFollowing(string) from inside your Read() loop. Thus, once you read past the last <orderNumber>, you will get an exception when another <quoteNumber> is not found.
I would suggest restructuring your code as follows:
var ns = ""; // Replace with #"http://intelliquip.com/integrationS..." can't see the full namespace from the XML image.
var list = new List<Tuple<string, string>>(); // List of (quoteNumber, orderNumber) values.
var xmlReader = XmlReader.Create(FilePath);
while (xmlReader.ReadToFollowing("quoteNumber", ns))
{
string quoteNumber = null;
string orderNumber = null;
using (var inner = xmlReader.ReadSubtree())
{
// We need to skip the insignificant whitespace around the CDATA nodes which ReadElementContentAsString() will not do.
while (inner.Read())
{
switch (xmlReader.NodeType)
{
case XmlNodeType.Text:
case XmlNodeType.CDATA:
quoteNumber += inner.Value;
break;
}
}
// After ReadSubtree() the reader is positioned on the </quoteNumber> element end.
}
// If the next orderNumber node is nmissing, ReadToFollowing() will read all the way past the next quoteNumber node.
// Use ReadToNextSibling() instead.
if (xmlReader.ReadToNextSibling("orderNumber", ns))
{
using (var inner = xmlReader.ReadSubtree())
{
while (inner.Read())
{
switch (xmlReader.NodeType)
{
case XmlNodeType.Text:
case XmlNodeType.CDATA:
orderNumber += inner.Value;
break;
}
}
}
}
if (quoteNumber != null && orderNumber != null)
list.Add(Tuple.Create(quoteNumber, orderNumber));
else
{
// Add error handling here
}
}
Notes:
CDATA is just an alternate way of encoding an XML character data node, see What does <![CDATA[]]> in XML mean? for details. XmlReader.Value will contain the unescaped value of an XML character data node regardless of whether it is encoded as a regular text node or a CDATA node.
It is unclear from your question whether there must be exactly one <quoteNumber> node in the XML file. Because of that I read the quote and order number pairs into a List<Tuple<string, string>>. After reading is complete you can check how many were read and add then to Globals.COData as appropriate.
XmlReader.ReadToFollowing() returns
true if a matching element is found; otherwise false and the XmlReader is in an end of file state.
Thus its return value needs to be check to make sure you don't try to read past the end of the file.
Your code doesn't attempt to handle situations where an <orderNumber> is missing. If it is, the code will may skip all the way past the next <quoteNumber> to read its order number. To avoid this possibility I use XmlReader.ReadToNextSibling() to limit the scope of the search to <orderNumber> nodes belonging to the same parent node.
By using XmlReader.ReadToFollowing("orderNumber") you hardcode your code to assume that the orderNumber node(s) have no namespace prefix. Rather than doing that, it would be safer to explicitly indicate the namespace they are in which seems to be something like http://intelliquip.com/integrationS... where the ... portion is not shown.
I recommend using XmlReader.ReadToFollowing("orderNumber", ns) where ns is the namespace the order and quote nodes are actually in.
XmlTextReader has been deprecated since .Net 2.0. Use XmlReader.Create() instead.
The XmlReader API is rather fussy to use. If your XML files are not large you might consider loading them into an XDocument and using LINQ to XML to query it.
For instance, your XmlReader code could be rewritten as follows:
var doc = XDocument.Load(FilePath);
XNamespace ns = ""; // Replace with #"http://intelliquip.com/integrationS..." can't see the full namespace from the XML image.
var query = from quote in doc.Descendants(ns + "quoteNumber")
let order = quote.ElementsAfterSelf(ns + "orderNumber").FirstOrDefault()
where order != null
select Tuple.Create(quote.Value, order.Value);
var list = query.ToList();
Which looks much simpler.
You might also consider replacing the Tuple<string, string> with a proper data model such as
public class Order
{
public string QuoteNumber { get; set; }
public string OrderNumber { get; set; }
}
Demo fiddle #1 here for XmlReader and #2 here for LINQ to XML.
I'm using a 3rd party XML parser (not my decision) and found it does something bad. Here is the inner part of an XML tag:
"Date=""2014-01-01"" Amounts=""100717.72 100717.72 100717.72 100717.72"""
To parse the attributes, the code does a .split on spaces, ignoring the quotes. This works fine as long as there's no strings with spaces, but here we are. It returns proper Date=2014-01-01 and semi-proper Amounts=100717.72, but then four more entries of just the numbers.
I have the C# code for the parser, and thought about replacing the spaces-inside-quotes with some other character, splitting, and the changing them back. But then I thought I should ask here first.
Is there a way to parse this text into two entries properly?
UPDATE: original XML follows (typed in from another computer, forgive me!)
<DetailAmounts Date="2014-01-01" Amounts="100717.72 100717.72 100717.72 100717.72" />
You should just use XmlSerializer to deserialize the data:
public class DetailAmounts
{
[XmlAttribute]
public DateTime Date { get; set; }
[XmlAttribute]
public string Amounts { get; set; }
}
// ...
var xml = "<DetailAmounts Date=\"2014-01-01\" Amounts=\"100717.72 100717.72 100717.72 100717.72\" />";
var serializer = new XmlSerializer(typeof(DetailAmounts));
using (var reader = new StringReader(xml))
{
var detailAmounts = (DetailAmounts)serializer.Deserialize(reader);
}
Or, you can use XElement to parse each individual values:
var xml = "<DetailAmounts Date=\"2014-01-01\" Amounts=\"100717.72 100717.72 100717.72 100717.72\" />";
var element = XElement.Parse(xml);
var detailAmounts = new
{
Date = (DateTime)element.Attribute("Date"),
Amounts = element.Attribute("Amounts").Value.Split(' ')
.Select(x => decimal.Parse(x, CultureInfo.InvariantCulture))
.ToArray()
};
I am writing a set of objects that must serialize to and from Xml, following a strict specification that I cannot change. One element in this specification can contain a mix of strings and elements in-line.
A simple example of this Xml output would be this:
<root>Leading text <tag>tag1</tag> <tag>tag2</tag></root>
Note the whitespace characters between the closing of the first tag, and the start of the second tag. Here are the objects that represents this structure:
[XmlRoot("root")]
public class Root
{
[XmlText(typeof(string))]
[XmlElement("tag", typeof(Tag))]
public List<object> Elements { get; set; }
//this is simply for the sake of example.
//gives us four objects in the elements array
public static Root Create()
{
Root root = new Root();
root.Elements.Add("Leading text ");
root.Elements.Add(new Tag() { Text = "tag1" });
root.Elements.Add(" ");
root.Elements.Add(new Tag() { Text = "tag2" });
return root;
}
public Root()
{
Elements = new List<object>();
}
}
public class Tag
{
[XmlText]
public string Text {get;set;}
}
Calling Root.Create(), and saving to a file using this method looks perfect:
public XDocument SerializeToXml(Root obj)
{
XmlSerializer serializer = new XmlSerializer(typeof(Root));
XDocument doc = new XDocument();
using (var writer = doc.CreateWriter())
{
serializer.Serialize(writer, obj);
}
return doc;
}
Serialization looks exactly like the xml structure at the beginning of this post.
Now when I want to serialize an xml file back into a Root object, I call this:
public static Root FromFile(string file)
{
XmlSerializer serializer = new XmlSerializer(typeof(Root));
XmlReaderSettings settings = new XmlReaderSettings();
XmlReader reader = XmlTextReader.Create(file, settings);
//whitespace gone here
Root root = serializer.Deserialize(reader) as Root;
return root;
}
The problem is here. The whitespace string is eliminated. When I call Root.Create(), there are four objects in the Elements array. One of them is a space. This serializes just fine, but when deserializing, there are only 3 objects in Elements. The whitespace string gets eliminated.
Any ideas on what I'm doing wrong? I've tried using xml:space="preserve", as well as a host of XmlReader, XmlTextReader, etc. variations. Note that when I use a StringBuilder to read the XmlTextReader, the xml contains the spaces as I'd expect. Only when calling Deserialize(stream) do I lose the spaces.
Here's a link to an entire working example. It's LinqPad friendly, just copy/paste: http://pastebin.com/8MkUQviB The example opens two files, one a perfect serialized xml file, the second being a deserialized then reserialized version of the first file. Note you'll have to reference System.Xml.Serialization.
Thanks for reading this novel. I hope someone has some ideas. Thank you!
It looks like a bug. Workaround seems to be replace all whitespaces and crlf in XML text nodes by
entities. Semantic equal entities (
) does not work.
<root>Leading text <tag>tag1</tag> <tag>tag2</tag></root>
is working for me.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Amazon Marketplace XML parsing
I am new to parsing XML in C# and I have some data from Amazon MWS library that is displayed below. I need to parse out various ItemAttributes such as ItemDimensions. I am use to JSON responses so I am not sure how to apply this to XML. Would it be possible from someone to point me in the right direction? I have Googled XML Parsing with C# but not valuable results were found to help me complete my tasks.
<GetMatchingProductResponse xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01">
<GetMatchingProductResult ASIN="1430225491" status="Success">
<Product>
<Identifiers>
<MarketplaceASIN>
<MarketplaceId>ATVPDKIKX0DER</MarketplaceId>
<ASIN>1430225491</ASIN>
</MarketplaceASIN>
</Identifiers>
<AttributeSets>
<ns2:ItemAttributes xml:lang="en-US">
<ns2:Author>Troelsen, Andrew</ns2:Author>
<ns2:Binding>Paperback</ns2:Binding>
<ns2:Brand>Apress</ns2:Brand>
<ns2:Edition>5</ns2:Edition>
<ns2:ItemDimensions>
<ns2:Height Units="inches">9.21</ns2:Height>
<ns2:Length Units="inches">7.48</ns2:Length>
<ns2:Width Units="inches">2.52</ns2:Width>
<ns2:Weight Units="pounds">5.80</ns2:Weight>
</ns2:ItemDimensions>
<ns2:IsAutographed>false</ns2:IsAutographed>
<ns2:IsEligibleForTradeIn>true</ns2:IsEligibleForTradeIn>
<ns2:IsMemorabilia>false</ns2:IsMemorabilia>
<ns2:Label>Apress</ns2:Label>
<ns2:Languages>
<ns2:Language>
<ns2:Name>english</ns2:Name>
<ns2:Type>Unknown</ns2:Type>
</ns2:Language>
<ns2:Language>
<ns2:Name>english</ns2:Name>
<ns2:Type>Original Language</ns2:Type>
</ns2:Language>
<ns2:Language>
<ns2:Name>english</ns2:Name>
<ns2:Type>Published</ns2:Type>
</ns2:Language>
</ns2:Languages>
<ns2:ListPrice>
<ns2:Amount>59.99</ns2:Amount>
<ns2:CurrencyCode>USD</ns2:CurrencyCode>
</ns2:ListPrice>
<ns2:Manufacturer>Apress</ns2:Manufacturer>
<ns2:NumberOfItems>1</ns2:NumberOfItems>
<ns2:NumberOfPages>1752</ns2:NumberOfPages>
<ns2:PackageDimensions>
<ns2:Height Units="inches">2.60</ns2:Height>
<ns2:Length Units="inches">9.20</ns2:Length>
<ns2:Width Units="inches">7.50</ns2:Width>
<ns2:Weight Units="pounds">5.80</ns2:Weight>
</ns2:PackageDimensions>
<ns2:PartNumber>9781430225492</ns2:PartNumber>
<ns2:ProductGroup>Book</ns2:ProductGroup>
<ns2:ProductTypeName>ABIS_BOOK</ns2:ProductTypeName>
<ns2:PublicationDate>2010-05-14</ns2:PublicationDate>
<ns2:Publisher>Apress</ns2:Publisher>
<ns2:SmallImage>
<ns2:URL>http://ecx.images-amazon.com/images/I/51h9Sju5NKL._SL75_.jpg</ns2:URL>
<ns2:Height Units="pixels">75</ns2:Height>
<ns2:Width Units="pixels">61</ns2:Width>
</ns2:SmallImage>
<ns2:Studio>Apress</ns2:Studio>
<ns2:Title>Pro C# 2010 and the .NET 4 Platform</ns2:Title>
</ns2:ItemAttributes>
</AttributeSets>
<Relationships/>
<SalesRankings>
<SalesRank>
<ProductCategoryId>book_display_on_website</ProductCategoryId>
<Rank>43011</Rank>
</SalesRank>
<SalesRank>
<ProductCategoryId>697342</ProductCategoryId>
<Rank>36</Rank>
</SalesRank>
<SalesRank>
<ProductCategoryId>3967</ProductCategoryId>
<Rank>53</Rank>
</SalesRank>
<SalesRank>
<ProductCategoryId>4013</ProductCategoryId>
<Rank>83</Rank>
</SalesRank>
</SalesRankings>
</Product>
</GetMatchingProductResult>
<ResponseMetadata>
<RequestId>440cdde0-fa76-4c48-bdd1-d51a3b467823</RequestId>
</ResponseMetadata>
</GetMatchingProductResponse>
I find "Linq To Xml" easier to use
var xDoc = XDocument.Parse(xml); //or XDocument.Load(filename);
XNamespace ns = "http://mws.amazonservices.com/schema/Products/2011-10-01";
var items = xDoc.Descendants(ns + "ItemAttributes")
.Select(x => new
{
Author = x.Element(ns + "Author").Value,
Brand = x.Element(ns + "Brand").Value,
Dimesions = x.Element(ns+"ItemDimensions").Descendants()
.Select(dim=>new{
Type = dim.Name.LocalName,
Unit = dim.Attribute("Units").Value,
Value = dim.Value
})
.ToList()
})
.ToList();
You could reinvent the wheel, or you could use Amazon's wheel (see #George Duckett's answer for the direct link):
Amazon Marketplace API
One option to address your question: if you want a tool that will enable you to work with your xml file, I would look at xsd.exe. MSDN for xsd.exe
This tool is able to generate classes from xml.
Otherwise, you can create a parser from the XDocument class that will allow you to use linq to build a parser such as #L.B noted in his post.
You have not made clear exactly what you need from the XML, so I cannot give you an objective answer. I'll begin by stating that there are many different ways to parse XML using .Net (and C# in your case, albeit they are similar with VB and C#).
The first one that I would look into is actually modeling your XML Data into .Net objects, more specifically, POCOs. To that class model you could add attributes that would bind or relate them to the XML and then all you'd need to do is pass the data and the class to a XML deserializer.
Now, if you don't need to retrieve the whole object, you can either use XDocument or XmlDocument. The fun part of XDocument is that its syntax in LINQ friendly, so you can parse you XML very simply.
XmlDocument is more old-style sequential method invocation, but achieves the same thing.
Let me illustrate. Consider a simpler XML, for simplicity sake's:
<body>
<h1>This is a text.</h1>
<p class="SomeClass">This is a paragraph</p>
</body>
(see what I did there? That HTML is a valid XML!)
I. Using A Deserializer:
First you model the classes:
[XmlRoot]
public class body
{
[XmlElement]
public h1 h1 { get; set; }
[XmlElement]
public p p { get; set; }
}
public class h1
{
[XmlText]
public string innerXML { get; set; }
}
public class p
{
[XmlAttribute]
public string id { get; set; }
[XmlText]
public string innerXML { get; set; }
}
Once you have your class model, you call the serializer.
void Main()
{
string xml =
#"<body>
<h1>This is a text.</h1>
<p id=""SomeId"">This is a paragraph</p>
</body>";
// Creates a stream that reads from the string
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(xml);
writer.Flush();
stream.Position = 0;
// Check the classes below before proceding.
XmlSerializer serializer = new XmlSerializer(typeof(body));
var obj = (body)serializer.Deserialize(stream);
// Check obj here with the debugger. All fields are filled.
}
II. Using XDocument
The example above makes for a very neat code, since you access everything typed. However, it demands a lot of setup work since you must model the classes. Maybe some simpler will suffice in your case. Let's say you want to get the attribute of the p element:
void Main()
{
string xml =
#"<body>
<h1>This is a text.</h1>
<p id=""SomeId"">This is a paragraph</p>
</body>";
// Creates a stream that reads from the string
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(xml);
writer.Flush();
stream.Position = 0;
// Using XDocument
var pAttrib = XDocument.Load(stream).Element("body").Element("p").Attribute("id").Value;
Console.Writeline(pAttrib);
}
Simple, huh? You can do more complex stuff throwing LINQ there... Let's try to find the element with id named "SomeId":
void Main()
{
string xml =
#"<body>
<h1>This is a text.</h1>
<p id=""SomeId"">This is a paragraph</p>
</body>";
// Creates a stream that reads from the string
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(xml);
writer.Flush();
stream.Position = 0;
// Using XDocument
var doc = XDocument.Load(stream);
var found = from body in doc.Elements("body")
from elem in body.Elements()
from attrib in elem.Attributes()
where attrib.Name == "id" && attrib.Value == "SomeId"
select elem;
foreach (var e in found) Console.WriteLine(e);
}
Hope it helps.
I'm new to C#. I'm building an application that persists an XML file with a list of elements. The structure of my XML file is as follows:
<Elements>
<Element>
<Name>Value</Name>
<Type>Value</Type>
<Color>Value</Color>
</Element>
<Element>
<Name>Value</Name>
<Type>Value</Type>
<Color>Value</Color>
</Element>
<Element>
<Name>Value</Name>
<Type>Value</Type>
<Color>Value</Color>
</Element>
</Elements>
I have < 100 of those items, and it's a single list (so I'm considering a DB solution to be overkill, even SQLite). When my application loads, I want to read this list of elements to memory. At present, after browsing the web a bit, I'm using XmlTextReader.
However, and maybe I'm using it in the wrong way, I read the data tag-by-tag, and thus expect the tags to be in a certain order (otherwise the code will be messy). What I would like to do is read complete "Element" structures and extract tags from them by name. I'm sure it's possible, but how?
To clarify, the main difference is that the way I'm using XmlTextReader today, it's not tolerant to scenarios such as wrong order of tags (e.g. Type comes before Name in a certain Element).
What's the best practice for loading such structures to memory in C#?
It's really easy to do in LINQ to XML. Are you using .NET 3.5? Here's a sample:
using System;
using System.Xml.Linq;
using System.Linq;
class Test
{
[STAThread]
static void Main()
{
XDocument document = XDocument.Load("test.xml");
var items = document.Root
.Elements("Element")
.Select(element => new {
Name = (string)element.Element("Name"),
Type = (string)element.Element("Type"),
Color = (string)element.Element("Color")})
.ToList();
foreach (var x in items)
{
Console.WriteLine(x);
}
}
}
You probably want to create your own data structure to hold each element, but you just need to change the "Select" call to use that.
Any particular reason you're not using XmlDocument?
XmlDocument myDoc = new XmlDocument()
myDoc.Load(fileName);
foreach(XmlElement elem in myDoc.SelectNodes("Elements/Element"))
{
XmlNode nodeName = elem.SelectSingleNode("Name/text()");
XmlNode nodeType = elem.SelectSingleNode("Type/text()");
XmlNode nodeColor = elem.SelectSingleNode("Color/text()");
string name = nodeName!=null ? nodeName.Value : String.Empty;
string type = nodeType!=null ? nodeType.Value : String.Empty;
string color = nodeColor!=null ? nodeColor.Value : String.Empty;
// Here you use the values for something...
}
It sounds like XDocument, and XElement might be better suited for this task. They might not have the absolute speed of XmlTextReader, but for your cases they sound like they would be appropriate and it would make dealing with fixed structures a lot easier. Parsing out elements would work like so:
XDocument xml;
foreach (XElement el in xml.Element("Elements").Elements("Element")) {
var name = el.Element("Name").Value;
// etc.
}
You can even get a bit fancier with Linq:
XDocument xml;
var collection = from el in xml.Element("Elements").Elements("Element")
select new { Name = el.Element("Name").Value,
Color = el.Element("Color").Value,
Type = el.Element("Type").Value
};
foreach (var item in collection) {
// here you can use item.Color, item.Name, etc..
}
You could use XmlSerializer class (http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx)
public class Element
{
public string Name { get; set; }
public string Type { get; set; }
public string Color { get; set; }
}
class Program
{
static void Main(string[] args)
{
string xml =
#"<Elements>
<Element>
<Name>Value</Name>
<Type>Value</Type>
<Color>Value</Color>
</Element>(...)</Elements>";
XmlSerializer serializer = new XmlSerializer(typeof(Element[]), new XmlRootAttribute("Elements"));
Element[] result = (Element[])serializer.Deserialize(new StringReader(xml));}
You should check out Linq2Xml, http://www.hookedonlinq.com/LINQtoXML5MinuteOverview.ashx