Getting the XmlNode value for each xml node - c#

I am using the below xml file
<?xml version="1.0" encoding="UTF-8"?>
<bookstore xmlns="urn:newbooks-schema">
<book>
<title>Books</title>
<price>20.00</price>
<attribute>
<fieldName>Books</fieldName>
<attributeStyle>ValueSet</attributeStyle>
<valueset>
<id>Part 1</id>
<values>
<displayName>Lord of the Rings</displayName>
</values>
</valueset>
</attribute>
</book>
<book>
<title>Books</title>
<price>20.00</price>
<attribute>
<fieldName>Books</fieldName>
<valueset>
<id>Part 1</id>
<values>
<displayName>Harry Potter</displayName>
</values>
</valueset>
</attribute>
</book>
</bookstore>
I am trying to get each node "book" in an XMLNodeList and I am looping the nodes to get the individual data of the node "values". I have used the below code and tried to achieve it But the valuenodes is always returning both the values nodes i.e., Lord of the Rings and the Harry Potter together and not in each loop. I want to achieve it one by one in a loop and not all together.
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(text);
var root = xmlDocument.DocumentElement;
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDocument.NameTable);
nsmgr.AddNamespace("bk", "urn:newbooks-schema");
XmlNodeList criterion = root.SelectNodes("bk:book[bk:title='Books']", nsmgr);
foreach (XmlNode criterionNode in criterion)
{
XmlNode xml = criterionNode.SelectSingleNode("//bk:valueset", nsmgr);
var valuesNodeExpression = "//bk:valueset/bk:values[../../bk:fieldName='Books']";
XmlNodeList valueNodes = criterionNode.SelectNodes(valuesNodeExpression, nsmgr);
}

I slightly refactored the code, giving more telling names to the variables.
// Here the previous code is unchanged.
var books = root.SelectNodes("bk:book[bk:title='Books']", nsmgr);
Console.WriteLine(books.Count);
foreach (XmlNode book in books)
{
var valueset = book.SelectSingleNode(".//bk:valueset", nsmgr);
var id = valueset.SelectSingleNode("./bk:id", nsmgr).InnerText;
var displayName = valueset.SelectSingleNode(".//bk:displayName", nsmgr).InnerText;
Console.WriteLine(id);
Console.WriteLine(displayName);
}

Related

C# XmlDocument how to get pointer to root element and iterate over children

In XML Document:
Foo.xml
<products>
<product>
<id>1</id>
<name>Foo</name>
</product>
<product>
<id>2</id>
<name>Bar</name>
</product>
</products>
How to get this root element, iterate over his child elements and get their properties?
Bar.cs
XmlDocument doc = new XmlDocument();
doc.Load(path + "/foo.xml");
XmlNode mainNode = doc.DocumentElement.SelectSingleNode("products");
XmlNode root = mainNode.FirstChild; //null
foreach (XmlNode node in mainNode)
{
int id = Convert.ToInt32(node["id"].InnerText);
string name = node["name"].InnerText);
list.Items.Add(id);
list.Items.Add(name);
}
This code implicates that mainNode is null. What is the best practise of doing that?
The DocumentElement is the outermost element of the XML, i.e. the <products> element. You can't select another <products> element below it.
What you can do:
XmlNode mainNode = doc.SelectSingleNode("products");
or
XmlNode mainNode = doc.DocumentElement;
or
XmlNode mainNode = doc.DocumentElement.SelectSingleNode("//products");
The second one is probably the fastest, since it does not need to parse and process a query. The last one is overkill and should be avoided for clean code reasons (KISS principle).

printing list of xml nodes in c#

I am need bit of help on getting list of xml nodes and printing them.
My code is as below:
XmlDocument doc = new XmlDocument();
doc.Load("To44532.xml");
XmlNode xn = doc.DocumentElement;
foreach (XmlNode xn2 in xn)
{ Console.WriteLine(xn2); }
Console.ReadLine();
I am new to c# please accept my apologies in advance for asking this basic question. So I wanted full list of nodes and then printing them in output.
I ended up with this piece of code because I wanted to debug one of the other code. The idea was that I wanted to display specific nodes in winforms. I tried if statement e.g. :
foreach (XmlNode node in doc.DocumentElement)
{
if (node.Equals("DbtItm"))
{ ..... }
Could you please advise whats the best way to achieve it?
You can select XML Nodes by Name.
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="children">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="web">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
For example to get only book author and book year from as above xml.
XmlDocument xml = new XmlDocument();
xml.Load("XMLFile1.xml");
XmlNodeList xnList = xml.SelectNodes("/bookstore/book");
foreach (XmlNode xn in xnList)
{
string author = xn["author"].InnerText;
string year = xn["year"].InnerText;
Console.WriteLine(author+"-"+year);
}

Unable to use InsertAfter for XmlDocument in c#

Hi below are the XML files which is master XML
<?xml version="1.0" encoding="utf-16"?>
<Verify>
<ver>
<ECU>
<values>
</values>
</ECU>
</ver>
</Verify>
I have multiple files which are of same structure as below
<?xml version="1.0" encoding="utf-16"?>
<Verify>
<ver>
<ECU>
<values>
</values>
</ECU>
</ver>
</Verify>
I want my output as
<?xml version="1.0" encoding="utf-16"?>
<Verify>
<ver>
<ECU>
<values>
</values>
</ECU>
<ECU>
<values>
</values>
</ECU>
<ECU>
<values>
</values>
</ECU>
</ver>
</Verify>
I am using below code to read first one as master xml
and other files from xmls folder. I want to add ECU node from these files under ECU node of master file.
XmlDocument xmlMaster = new XmlDocument();
xmlMaster.Load(#"C:\MasterXMLFile.xml");
XmlElement masterRoot = xmlMaster.DocumentElement;
XmlNode masterParent = masterRoot.LastChild.LastChild;
var downloadfolder = #"C:\AllXMLs\xmls\";
string[] files = Directory.GetFiles(downloadfolder);
foreach (var xx in files)
{
XmlNode masterNode = masterRoot.LastChild.LastChild;
XmlDocument xdoc = new XmlDocument();
xdoc.Load(xx);
XmlElement root = xdoc.DocumentElement;
XmlElement tempNode = (XmlElement)root.LastChild.LastChild;
masterRoot.InsertAfter(tempNode, masterRoot.SelectSingleNode("//ECU").ParentNode);
}
xmlMaster.Save(#"C:\mergeg.xml");
I am getting error at InsertAfter statement as Object reference not set to an instance of an object.
Please suggest me any solution.
Your tempNode is from xdoc document context. You should import it to xmlMaster document context:
XmlNode importedECU = xmlMaster.ImportNode(tempNode, true);
Also instead of InsertAfter it's better to use AppendChild and append new ECU nodes as children of master ver element:
var masterVer = masterRoot.SelectSingleNode("//ver");
foreach(var file in files)
{
var xdoc = new XmlDocument();
xdoc.Load(file);
var tempNode = xdoc.DocumentElement.LastChild.LastChild;
var importedECU = xmlMaster.ImportNode(tempNode, true);
masterVer.AppendChild(importedECU);
}
Your InsertAfter should be on the parentNode of the node you want to insert after, so the parent of tempNode.

Get XML content from XmlNodeList

I have a question that may seem very simple, but it's giving me a headache. I have this XML file that has multiple entries, like:
<books>
<book>
<id>1</id>
<firstCover>
<author name="**" age="**" />
<title name="zz" font="yyy" size="uuu"/>
</firstCover>
<lastCover>
</lastCover>
</book>
<book>
<id>2</id>
<firstCover>
<author name="**" age="**" />
<title name="zz" font="yyy" size="uuu"/>
</firstCover>
<lastCover>
</lastCover>
</book>
</books>
Now, in order to get the XML content for first cover of book with id=1, I do this:
XmlNodeList b = root.SelectNodes("/books/book[contains(id,1)]/firstCover");
Then I would really need to take the whole content of what's inside the firstCover for that book :
<author name="**" age="**" />
<title name="zz" font="yyy" size="uuu"/>
and insert it into an XmlElement. This is where I'm stucked. I know I can do it with a foreach loop in XmlNodeList, but is there a more simple way?
I'm guessing you want to actually insert it into an XMLElement in another XMLDocument.
Is this what you are looking for?
XmlDocument sourceDoc = new XmlDocument();
//This is loading the XML you present in your Question.
sourceDoc.LoadXml(xmlcopier.Properties.Resources.data);
XmlElement root = sourceDoc.DocumentElement;
XmlElement b = (XmlElement)root.SelectSingleNode("/books/book[contains(id,1)]/firstCover");
XmlDocument destDoc = new XmlDocument();
XmlElement destRoot = destDoc.CreateElement("base");
destDoc.AppendChild(destRoot);
XmlElement result = destDoc.CreateElement("firstCover");
result.InnerXml = b.InnerXml;
destRoot.AppendChild(result);
destDoc.Save("c:\\test.xml");

Adding a node to XMl

the XML
<bookstore xmlns="http://www.contoso.com/books"
xmlns:g="http://www.contoso.com/genre">
<book g:genre="novel" publicationdate="2010-03-01" ISBN="1-123456-15-0">
<title>61 Hours</title>
<author xmlns="http://www.contoso.com/author">
<first-name>Lee</first-name>
<last-name>Child</last-name>
</author>
<price>6.99</price>
</book>
<bookstore>
I need to add a book node to it.. My code reads like this
strpath = "C:\\BookStore.xml";
XmlDocument doc = new XmlDocument();
doc.Load(strpath);
XmlNode root = doc.DocumentElement;
XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
nsMgr.AddNamespace("b", "http://www.contoso.com/books");
nsMgr.AddNamespace("g", "http://www.contoso.com/genre");
nsMgr.AddNamespace("a", "http://www.contoso.com/author");
// Create a Book element and populate its attributes
System.Xml.XmlElement XmlElementbook = doc.CreateElement("book");
//create the three attributes to hold the values
XmlElementbook.SetAttribute("g:genre";"novel5");
XmlElementbook.SetAttribute("publicationdate", "2010-11-03");
XmlElementbook.SetAttribute("ISBN", "1-00000-00-00");
// Insert the new element into the XML tree
// Create a new XML element and populate its attributes
System.Xml.XmlElement myXmlElementTitle = doc.CreateElement("title");
myXmlElementTitle.InnerText = "TestBook";
// Insert the new element under the node we created
XmlElementbook.AppendChild(myXmlElementTitle);
System.Xml.XmlElement myXmlElementAuthor = doc.CreateElement("author");
myXmlElementAuthor.SetAttribute("xmlns", ("http://www.contoso.com/author"));
System.Xml.XmlElement myXmlElementFirstname = doc.CreateElement("first-name");
myXmlElementFirstname.InnerText = "Bikram";
myXmlElementAuthor.AppendChild(myXmlElementFirstname);
System.Xml.XmlElement myXmlElementLastname = doc.CreateElement("last-name");
myXmlElementLastname.InnerText = "Mann";
myXmlElementAuthor.AppendChild(myXmlElementLastname);
XmlElementbook.AppendChild(myXmlElementAuthor);
// Price
System.Xml.XmlElement myXmlElementPrice = doc.CreateElement("price");
myXmlElementPrice.InnerText = "2.99";
// Insert the new element under the node we created
XmlElementbook.AppendChild(myXmlElementPrice);
//append the whole node to file
doc.DocumentElement.AppendChild(XmlElementbook);
doc.Save("C:\\BookStore.xml");
The only thing is the New node that gets written looks like
<bookstore xmlns="http://www.contoso.com/books"
xmlns:g="http://www.contoso.com/genre">
<book g:genre="novel" publicationdate="2010-03-01" ISBN="1-123456-15-0">
<title>61 Hours</title>
<author xmlns="http://www.contoso.com/author">
<first-name>Lee</first-name>
<last-name>Child</last-name>
</author>
<price>6.99</price>
</book>
***<book genre="novel5"
publicationdate="2010-11-03"
ISBN="1-00000-00-00"
xmlns="">
<title>TestBook</title>
<author xmlns="http://www.contoso.com/author">
<first-name>Bikram</first-name>
<last-name>Mann</last-name>
</author>
<price>2.99</price>
</book>***
<bookstore>
It has an extra XMLNS="" and g: is missing in the node
What Am i doing Wrong Please...
You want:
System.Xml.XmlElement XmlElementbook =
doc.CreateElement("book","http://www.contoso.com/books");
and
XmlElementbook.SetAttribute("genre","http://www.contoso.com/genre","novel5");
to create these nodes in the correct namespaces.

Categories

Resources