Unable to use InsertAfter for XmlDocument in c# - 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.

Related

Access Child nodes with namespace using xpath

How can I read the content of the childnotes using Xpath?
I have already tried this:
var xml = new XmlDocument();
xml.Load("server-status.xml");
var ns = new XmlNamespaceManager(xml.NameTable);
ns.AddNamespace("ns", "namespace");
var node = xml.SelectSingleNode("descendant::ns:server[ns:ip-address]", ns)
Console.WriteLine(node.InnerXml)
But I only get a string like this:
<ip-address>127.0.0.50</ip-address><name>Server 1</name><group>DATA</group>
How can I get the values individually?
Xml file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<server-status xmlns="namespace">
<server>
<ip-address>127.0.0.50</ip-address>
<name>Server 1</name>
<group>DATA</group>
</server>
</server-status>
You're using XML namespaces in XPath correctly.
However, your original XPath,
descendant::ns:server[ns:ip-address]
says to select all ns:server elements with ns:ip-address children.
If you wish to select the ns:ip-address children themselves, instead use
descendant::ns:server/ns:ip-address
Similarly, you could select ns:name or ns:group elements.

Getting the XmlNode value for each xml node

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);
}

Xml parser doesn't work

<?xml version="1.0" encoding="utf-8"?>
<response list="true">
<audio>
<aid>253663595</aid>
<artist>Example</artist>
<duration>389</duration>
<lyrics_id>57485771</lyrics_id>
<genre>18</genre>
</audio>
<audio>
<aid>253663595</aid>
<artist>Example1</artist>
<duration>400</duration>
<lyrics_id>57485772</lyrics_id>
<genre>20</genre>
</audio>
</response>
Source code
XmlDocument allAudio = new XmlDocument();
allAudio.Load(#"e:\Audio.xml");
StreamWriter write_text = File.CreateText(#"e:\Audio.txt");
XmlNodeList audioNodes = allAudio.GetElementsByTagName("audio");
foreach (XmlNode audioNode in audioNodes)
{
XmlNode artistNode = audioNode["artist"];
write_text.WriteLine(String.Format("{0}", artistNode.Value));
}
write_text.Close();
Hi, I can't parse xml. I want write some node values in file, but as result I get an empty txt file.
You want: artistNode.InnerText
Not: artistNode.value

Split xml file based on nodes

I have an XML doc which looks roughly like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Multiple xmlns:ns2="someNs2" xmlns="someGenericNs" xmlns:ns4="someNs4" xmlns:ns3="someNs3">
<Single>
<Id>60000</Id>
<Type>Activate</Type>
<Payload>
<ns3:Activation>
<ns3:Parent>
<ns3:TypeId>113</ns3:TypeId>
<ns3:TypeName>TestApplication</ns3:TypeName>
</ns3:Parent>
<ns3:Children>
<ns3:Child>
<ns3:Key>someKey</ns3:Key>
<ns3:ChildTypeName>BadAppType1</ns3:ChildTypeName>
</ns3:Child>
<ns3:Child>
<ns3:Key>someOtherKey</ns3:Key>
<ns3:ChildTypeName>GoodAppType1</ns3:ChildTypeName>
</ns3:Child>
</ns3:Children>
</ns3:Activation>
</Payload>
</Single>
</Multiple>
If the file contains multiple "Child" nodes i would like to split it into more files, 1 file for each existing child node. Something like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Multiple xmlns:ns2="someNs2" xmlns="someGenericNs" xmlns:ns4="someNs4" xmlns:ns3="someNs3">
<Single>
<Id>60000</Id>
<Type>Activate</Type>
<Payload>
<ns3:Activation>
<ns3:Parent>
<ns3:TypeId>113</ns3:TypeId>
<ns3:TypeName>TestApplication</ns3:TypeName>
</ns3:Parent>
<ns3:Children>
<ns3:Child>
<ns3:Key>someOtherKey</ns3:Key>
<ns3:ChildTypeName>GoodAppType2</ns3:ChildTypeName>
</ns3:Child>
</ns3:Children>
</ns3:Activation>
</Payload>
</Single>
</Multiple>
And then a new XmlDoc containing the other "Child" node. Can this be achieved through LINQ?
My code so far is:
private bool HasMoreThanOneChild(string xml) {
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
if (doc.GetElementsByTagName("ns3:Child").Count > 1)
{
return true;
}
return false;
}
public List<string> DoSomething(XmlDocument doc){
if(HasMoreThanOneChild(doc.InnerXml))
return Split(doc);
}
I returned a List there because I'm more interested in the "InnerXML" once the doc is split. But I am at a loss of how to implement this split, if it is possible.
XNamespace ns="someNs3";
//get all Child elements
var childElements=doc.Descendants().Elements(ns+"Child").ToList();
//remove those child elements
doc.Descendants().Elements(ns+"Child").ToList().ForEach(x=>x.Remove());
int i=1;
foreach(var child in childElements)
{
//add that child to children element
doc.Descendants().Elements(ns+"Children").First().Add(child);
//save it to new file!
doc.Save("file"+i+".xml");
doc.Descendants().Elements(ns+"Child").ToList().ForEach(x=>x.Remove());
i++;
}

Get entire XML except root element

<Employees>
<Product_Name>
<hello1>product1</hello1>
<hello2>product2</hello2>
<hello3>product3</hello3>
<hello4>product4</hello4>
</Product_Name>
<product_Price>
<hello1>111</hello1>
<hello2>222</hello2>
<hello3>333</hello3>
<hello4>444</hello4>
</product_Price>
</Employees>
is it possible to convert the following XML to the XML shown below using C#. I tried using remove function but it didn't work. I also tried to get the value of root node. Didn't work
<Product_Name>
<hello1>product1</hello1>
<hello2>product2</hello2>
<hello3>product3</hello3>
<hello4>product4</hello4>
</Product_Name>
<product_Price>
<hello1>111</hello1>
<hello2>222</hello2>
<hello3>333</hello3>
<hello4>444</hello4>
</product_Price>
If you just want to fetch the inner xml,you can use the XmlReader's ReadInnerXml.The innerXML is fetched as a string(skipping the root node).
var xmlReader = XElement.Load("data.xml").CreateReader();
xmlReader.MoveToContent();
string innerXml = xmlReader.ReadInnerXml();
If you have access to Linq to XML, you should you XDocument.
caveat: I believe your xml is malformed - you should have something like:
<?xml version="1.0" encoding="utf-8"?>
Add the first xml tag to the xml.
string xml = #"<?xml version="1.0" encoding="utf-8"?>
<Employees>
<Product_Name>
<hello1>product1</hello1>
<hello2>product2</hello2>
<hello3>product3</hello3>
<hello4>product4</hello4>
</Product_Name>
<product_Price>
<hello1>111</hello1>
<hello2>222</hello2>
<hello3>333</hello3>
<hello4>444</hello4>
</product_Price>
</Employees>";
XDocument xDoc = XDocument.Parse(xml);
// get the elements
var rootElements = xDoc.Root.Elements();
Alternatively, you can load the xml from a file:
XDocument xDoc = XDocument.Load("xmlFile.xml");
You can store it as XmlNodeList to be well-formed. Here's a working example of how to do it:
XmlDocument xml= new XmlDocument();
xml.LoadXml(#"<Employees>
<Product_Name>
<hello1>product1</hello1>
<hello2>product2</hello2>
<hello3>product3</hello3>
<hello4>product4</hello4>
</Product_Name>
<product_Price>
<hello1>111</hello1>
<hello2>222</hello2>
<hello3>333</hello3>
<hello4>444</hello4>
</product_Price>
</Employees>");
var nodeList = xml.SelectNodes("Employees");
foreach (XmlNode node in nodeList)
{
Console.WriteLine(node.InnerXml); //this will give you your desired result
}

Categories

Resources