C# Xml Parsing from StringBuilder - c#

I have a StringBuilder with the contents of an XML file. Inside the XML file is a root tag called <root> and contains multiple <node> tags.
I'd like to parse through the XML to read values of tags within in s, but not sure how to do it.
Will I have to use some C# XML data type for this?
Thanks in advance

StringBuilder sb = new StringBuilder (xml);
TextReader textReader = new StringReader (sb.ToString ());
XDocument xmlDocument = XDocument.Load (textReader);
var nodeValueList = from node in xmlDocument.Descendants ("node")
select node.Value;

You should use classes available in either System.Xml or System.Xml.Linq to parse XML.
XDocument is part of the LINQ extensions for XML and is particularly easy to use if you need to parse through an arbitrary structure. I would suggest using it rather than XmlDocument (unless you have legacy code or are not on .NET 3.5).
Creating an XDocument from a StringBuilder is straightforward:
var doc = XDocument.Parse( stringBuilder.ToString() );
From here, you can use FirstNode, Descendents(), and the many other properties and methods available to walk and examine the XML structure. And since XDocument is designed to work well with LINQ, you can also write queries like:
var someData = from node in doc.Descendants ("yourNodeType")
select node.Value; // etc..

If you are just looking the specifically named nodes then you don't need to load the document into memory, you can process it yourself with an XmlReader.
using(var sr = new StringReader(stringBuilder.ToString)) {
using(var xr = XmlReader.Create(sr)) {
while(xr.Read()) {
if(xr.IsStartElement() && xr.LocalName == "node")
xr.ReadElementString(); //Do something here
}
}
}

use XDocument.Parse(...)

There are several objects at your disposal for working with XML. Look at the System.Xml namespace for objects such as XmlDocument as well as the XmlReader and XmlWriter families of objects. If using C# 3.0+, look at the System.Xml.Linq namespace and the XDocument class.

If you're looking to read all the values in the XML file , you could look into deserializing the XML into a C# data Object.
Deserializing XML into class obj in C#

Yes, I suggest you use an XmlDocument object to parse the content of your string.
Here is an example who print all inner text contained in your tags:
var doc=new XmlDocument();
doc.LoadXml(stringBuilder.TosTring());
XmlNodeList elemList = doc.GetElementsByTagName("node");
for (int i=0; i < elemList.Count; i++)
{
XmlNode node=elemList[i];
Console.WriteLine(node.InnerText);
}
using Node object members, you can also easily extract all you attributes .

Related

Can DataSet be loaded into XmlDocument?

I see code example from Microsoft here how to convert DataSet object into XmlDataDocumentto work with XML better but this class is going to be depreicated.
It means we should perhaps work with XmlDocument class but can we convert a DataSet into XmlDocument?
This is the part of the code of interest: (basically I want to extract certain nodes)
XmlDataDocument xmlDoc = new XmlDataDocument(dataSet);
XmlNodeList nodeList = xmlDoc.DocumentElement.SelectNodes(
"descendant::Customers[*/OrderDetails/ProductID=43]");
DataRow dataRow;
foreach (XmlNode xmlNode in nodeList)
{
dataRow = xmlDoc.GetRowFromElement((XmlElement)xmlNode);
if (dataRow != null)
Console.WriteLine(dataRow[0]);
}
You can write directly to an XmlDocument by creating an XPathNavigator for the document then writing the DataSet to it directly AppendChild() like so:
var doc = new XmlDocument();
var navigator = doc.CreateNavigator();
using (var writer = navigator.AppendChild())
{
dataSet.WriteXml(writer);
}
However, if you are rewriting your code anyway, you should consider upgrading to XDocument from LINQ to XML which easily supports LINQ queries as well as XPath queries:
var doc = new XDocument();
using (var writer = doc.CreateWriter())
{
dataSet.WriteXml(writer);
}
Either option will be more performant than serializing the DataSet to an XML string then parsing the string.
Notes:
Unlike XmlDataDocument there is no dynamic link maintained between the XmlDocument or XDocument and the DataSet. Changes to one are not reflected in the other after creation.
You might consider whether reading XML into both a DataSet and XDocument / XmlDocument is really required. Consider simplifying your design by using one or the other, but not both.
Demo fiddle here.

Read multiple XML files into a XML class structure

I would like to Read and Deserialize more than one XML file into my XML class structure given a list of strings consisting of file names.
Obviously when reading ONE xml file, you can go like this:
XmlRoot file = null;
XmlSerializer ser = new XmlSerializer(typeof(XmlRoot));
using (XmlReader read = XmlReader.Create(FileName))
{
file = (XmlRoot)ser.Deserialize(read);
{
Which will deserialize the XML file into the class structure?
It is not possible to have a list with file names and use a foreach loop to iterate over them, reading and deserializing one by one as it would theoretically result into multiple root elements being read, deserialized and replicated in the class structure.
So in general I would like to deserialize each file and append the required master elements to a root object.
Does anyone know how to accomplish this? It would be of great help.
Thanks in advance!
PS: Excuse me for my English, as I am not a native speaker. If you need further information, just tell me!
I managed to solve the problem for myself.
First i created a XDocument for the first file i read, afterwards i iterate through the other documents creating a new XDocument for every xml file and try to get the elements after the root (Language in my case) and add it to the root of the XDocument created outside the loop.
XDocument lDoc = new XDocument();
int counter = 0;
foreach (var fileName in multipleFileNames)
{
try
{
counter++;
if (lCounter <= 1)
{
doc = XDocument.Load(fileName);
}
else
{
XDocument doc2 = XDocument.Load(fileName);
IEnumerable<XElement> elements = doc2.Element("Language")
.Elements();
doc.Root.Add(elements);
}
}
return Deserialize(lDoc);
Afterwards i call the Deserialize method, deserializing my created XDocument like this:
public static XmlLanguage Deserialize(XDocument doc)
{
XmlSerializer ser = new XmlSerializer(typeof(XmlLanguage));
return (XmlLanguage)ser.Deserialize(doc.CreateReader());
}

How to parse the below xml string in c#

I have the below xml string in one string variable.
string xmlString = "<a:ORegions>
<a:ID>1</a:ID>
<a:regionCode>US</a:regionCode>
</a:ORegions>
<a:ORegions>
<a:ID>2</a:ID>
<a:regionCode>CANADA</a:regionCode>
</a:ORegions>
<a:ORegions>
<a:ID>3</a:ID>
<a:regionCode>ASIA</a:regionCode>
</a:ORegions>
Now i want to access regionCode values, that is US, CANADA, ASIA
How i can do that using c#. I am new to xml parsing.
You can deserialize that string (assuming you fix the various syntax errors) via the System.Xml namespace classes, particularly XmlDocument, such as with its Load method. To access the namespaces (a in a:Oregions and such is a namespace), you'll want an XmlNamespaceManager. You'd then register the namespaces (they must be defined somewhere) with the manager and use that when querying the XmlDocument.
Use LinqToXml
var doc = XDocument.Parse(xmlString);
You can then access elements, values and attributes within:
XNamespace xmlNamespace = "a";
//e.g. Retrieve's a list of regioncodes...
var ids = doc.Elements(xmlNamespace + "ORegions")
.Select(r => r.Element("regionCode").Value);
XmlDocument document = new XmlDocument();
document.Load(filePath);
foreach (XmlNode node in document.GetElementsByTagName("a:regionCode"))
Console.WriteLine(node.InnerText);

Xml within an Xml

I basically want to know how to insert a XmlDocument inside another XmlDocument.
The first XmlDocument will have the basic header and footer tags.
The second XmlDocument will be the body/data tag which must be inserted into the first XmlDocument.
string tableData = null;
using(StringWriter sw = new StringWriter())
{
rightsTable.WriteXml(sw);
tableData = sw.ToString();
}
XmlDocument xmlTable = new XmlDocument();
xmlTable.LoadXml(tableData);
StringBuilder build = new StringBuilder();
using (XmlWriter writer = XmlWriter.Create(build, new XmlWriterSettings { OmitXmlDeclaration = true }))
{
writer.WriteStartElement("dataheader");
//need to insert the xmlTable here somehow
writer.WriteEndElement();
}
Is there an easier solution to this?
Use importNode feature in your document parser.
You can use this code based on CreateCDataSection method
// Create an XmlCDataSection from your document
var cdata = xmlTable.CreateCDataSection("<test></test>");
XmlElement root = xmlTable.DocumentElement;
// Append the cdata section to your node
root.AppendChild(cdata);
Link : http://msdn.microsoft.com/fr-fr/library/system.xml.xmldocument.createcdatasection.aspx
I am not sure what you are really looking for but this can show how to merge two xml documents (using Linq2xml)
string xml1 =
#"<xml1>
<header>header1</header>
<footer>footer</footer>
</xml1>";
string xml2 =
#"<xml2>
<body>body</body>
<data>footer</data>
</xml2>";
var xdoc1 = XElement.Parse(xml1);
var xdoc2 = XElement.Parse(xml2);
xdoc1.Descendants().First(d => d.Name == "header").AddAfterSelf(xdoc2.Elements());
var newxml = xdoc1.ToString();
OUTPUT
<xml1>
<header>header1</header>
<body>body</body>
<data>footer</data>
<footer>footer</footer>
</xml1>
You will need to write the inner XML files in CDATA sections.
Use writer.WriteCData for such nodes, passing in the inner XML as text.
writer.WriteCData(xmlTable.OuterXml);
Another option (thanks DJQuimby) is to encode the XML to some XML compatible format (say base64) - note that the encoding used must be XML compatible and that some encoding schemes will increase the size of the encoded document (base64 adds ~30%).

Overwrite specific XML attributes

Let's say I have a file like this:
<outer>
<inner>
<nodex attr="value1">text</attr>
<nodex attr="value2">text</attr>
</inner>
</outer>
Basically what I want to do is, in C# (constrained to .net 2.0 here), this (pseudocode):
foreach node
if(node eq 'nodex')
update attr to newvalue
When complete, the xml file (on disk) should look like:
<outer>
<inner>
<nodex attr="newvalue1">text</attr>
<nodex attr="newvalue2">text</attr>
</inner>
</outer>
These two look marginally promising:
Overwrite a xml file value
Setting attributes in an XML document
But it's unclear whether or not they actually answer my question.
I've written this code in the meantime:
Here's a more minimal case which works:
public static void UpdateXML()
{
XmlDocument doc = new XmlDocument();
using (XmlReader reader = XmlReader.Create("XMLFile1.xml"))
{
doc.Load(reader);
XmlNodeList list = doc.GetElementsByTagName("nodex");
foreach (XmlNode node in list)
{
node.Attributes["attr"].Value = "newvalue";
}
}
using (XmlWriter writer = XmlWriter.Create("XMLFile1.xml"))
{
doc.Save(writer);
}
}
The fastest solution would be to use a loop with XmlTextReader/XmlTextWriter. That way you do not need to load the whole xml in memory.
In pseudocode:
while (reader.read)
{
if (reader.Node.Name == "nodex")
......
writer.write ...
}
You can check here for ideas.
Here is a sample script that can be run from LinqPad
var x = #"<outer>
<inner>
<nodex attr=""value1"">text</nodex>
<nodex attr=""value2"">text</nodex>
</inner>
</outer>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(x);
foreach (XmlNode n in doc.SelectNodes("//nodex"))
{
n.Attributes["attr"].Value = "new" + n.Attributes["attr"].Value.ToString();
}
doc.OuterXml.Dump();
As starting point you can show us what you have tried, you could use XPATH to select the nodes you want to modify, search for select node by attribute value in xpath.
After you have found the nodes you want to update you can reassign the attribute value as needed with a normal assignment.

Categories

Resources