I have a xml like below
<ProcessInvoice>
<ApplicationArea>
<CreationDateTime>2016-06-01 13:15:36</CreationDateTime>
<ApplicationGroup>BBEX</ApplicationGroup>
<MessageType>PROCESSINVOICE</MessageType>
</ApplicationArea>
</ProcessInvoice>
Now I have path and value to add, but it is dynamic.
It can be like following
path-/ProcessInvoice/ApplicationArea/UserArea/Sample1
value-001
path-/ProcessInvoice/ApplicationArea/UserArea/UserAreaLine/Sample1
value-002
if the path is present then i have to add the value, else modify the value.
I can split the path and loop through to find till what node is present and what i have to add but I think there might be more elegant way of doing this.Please help me with the best approach to solve this?
Edit
Note- I will prefer XDocument And XElement.
May be I didnt explain properly.
My xml and node path both are dynamic.
There might be situation where multiple nodes are missing from my xml.
Now problem is i need to identify upto which node is existing in xml and which nodes i need to create.
Thanks
If "Sample1" node always exist, the code will look like this:
XmlDocument doc = new XmlDocument();
doc.Load(FILE);
var userArea = DocumentElement["ProcessInvoice"]["ApplicationArea"]["UserArea"];
foreach (XmlNode element in userArea.ChildNodes)
{
if (element.Name== "Sample1" )
{
XmlNode node == element;
node.InnerText ="001";
}
else if (element.Name == "UserAreaLine")
{
XmlNode node == element["Sample1"];
node.InnerText ="002";
}
}
Related
I am trying to read a file produced by another developer. The file looks something like this. I am trying to read in the value for 'ProfileName', but when I look at the object in memory, I see null for the Value (capital V) attribute. The only place I can see the string "GolfLeague-Dual" is in the outerxml attribute, but I would have to parse through a bunch of just to get it.
<?xml version="1.0"?>
<TopNode>
<ProfileSettings>
<ProfileName value="GolfLeague-Dual" />
</ProfileSettings>
</TopNode>
Here is my code to try to read this:
XmlDocument doc = new XmlDocument();
doc.Load(directory + #"\Settings.xml");
XmlElement root = doc.DocumentElement;
XmlNodeList nodes = root.SelectNodes("//ProfileSettings");
foreach (XmlNode node in nodes) {
Console.WriteLine(node["ProfileName"].Value);
}
Your code is trying to get the inner value of the node, not an attribute called value. Try this instead...
foreach (XmlNode node in nodes) {
Console.WriteLine(node["ProfileName"].Attributes["value"].Value);
}
Here's a working dotnetfiddle...
https://dotnetfiddle.net/pmJKbX
I try to rename any node starts with "NP" to "NP" in an XmlDocument. I only found this related questoin. based on the most up-voted answer I wrote:
XmlNodeList npNodeList = PSbank.SelectNodes("//*[starts-with(name(), 'NP')]");
foreach (XmlNode npNode in npNodeList)
{
// create new (renamed) Content node
XmlNode newNode = PSbank.CreateElement("NP");
// [if needed] copy existing Content children
newNode.InnerXml = npNode.InnerXml;
// replace existing Content node with newly renamed Content node
npNode.ParentNode.InsertBefore(newNode, npNode);
npNode.ParentNode.RemoveChild(npNode);
}
However, it seems it doesn't work in my case. When an NPX node contains other NPX nodes, the inner nodes are not replaced because the code manipulates XmlDocument and replaces the outer node with a new created node that contains the old innerXml.
Example Xml:
<S>
<NPC>
<NP> A </NP>
<NPA> B </NPA>
</NPC>
<NPD>
C
</NPD>
</S>
I look for a more general and elegant answer for such a problem.
I'd do this with LINQ to XML, it's a lot easier and cleaner. Firstly, it's generally a much nicer library, and secondly: XElement.Name is mutable.
var doc = XDocument.Parse(xml); // or use XDocument.Load
foreach (var element in doc.Descendants())
{
if (element.Name.LocalName.StartsWith("NP"))
{
element.Name = "NP";
}
}
See this fiddle for a working demo.
I have an XmlWriter that contains a xml that looks like the one below, just with a lot more nodes. what's the fastest and best way to remove all the ARTIST node from this xml ?
<CATALOG>
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
</CD>
<CD>
<TITLE>Hide your heart</TITLE>
<ARTIST>Bonnie Tyler</ARTIST>
</CD>
</CATALOG>
As long as the file isn't gigabytes XmlDocument should be fine:
XmlDocument XDoc = new XmlDocument();
XDoc.Load(MapPath(#"~\xml\test.xml"));
XmlNodeList Nodes = XDoc.GetElementsByTagName("ARTIST");
foreach (XmlNode Node in Nodes)
Node.ParentNode.RemoveChild(Node);
XDoc.Save(MapPath(#"~\xml\test_out.xml"));
When I tried Steve's solution I received the following error "The element list has changed. The enumeration operation failed to continue". I know it is a bit of a hack but to get around this I used the following:
//Load XML
XmlDocument XDoc = new XmlDocument();
XDoc.Load(MapPath(#"~\xml\test.xml"));
//Get list of offending nodes
XmlNodeList Nodes = XDoc.GetElementsByTagName("ARTIST");
//Loop through the list
while (Nodes.Count != 0) {
foreach (XmlNode Node in Nodes) {
//Remove the offending node
Node.ParentNode.RemoveChild(Node); //<--This line messes with our iteration and forces us to get a new list after each remove
//Stop the loop
break;
}
//Get a refreshed list of offending nodes
Nodes = XDoc.GetElementsByTagName("ARTIST");
}
//Save the document
XDoc.Save(newfile);
I was in a bind and needing something quick and this got the job done.
From the way your question is worded, I'm assuming that you have an XmlWriter that has been used to write an XmlDocument and you want to manipulate what it is going to write before flush is called.
I'm afraid that what you're trying to do may be impossible. The XmlWriter is not meant to manipulate XML before it is written to a destination stream.
I try to remove some XmlElements from my Xml file in C#2.0.
I can remove it successfully with XmlNode.Remove() method. But there is no Remove method in XmlElement.
I googled and found this.
elements are a type of node. In fact, if you look at the members of XmlNode and XmlElement in the .NET Framework, you will see that they are very much alike, but XmlElement has more going on. It inherits XmlNode and then is further customized. This is because an element is more specialized. A node is more general in scope. The document is a node, a processing instruction is a node, and so forth. Elements are different. If you look at the XmlNodeType property of an element, you will see that it is Element, one of the many types of nodes you find.
If element are a type of node, then why I can't use remove command. Then how?
XmlDocument doc_AlarmSettingUp = new XmlDocument();
doc_AlarmSettingUp.Load(xmlFile_AlarmSettingUp);
XmlNode rootDest = doc_AlarmSettingUp.SelectSingleNode("/Equipment/AlarmSettingUp/EnabledALIDs");
foreach (XmlElement el_AlarmSettingUp in doc_AlarmSettingUp.SelectNodes("/Equipment/AlarmSettingUp/EnabledALIDs/ALID"))
{
XmlElement outEl;
if (lookup.TryGetValue(el_AlarmSettingUp.GetAttribute("alid"), out outEl))
{
// exists; element now in "other"
// Console.WriteLine("exists");
}
else
{
// doesn't exist
Console.WriteLine("doesn't exist");
// Then How can I remove element with an element method? Thanks.
}
}
The following code should work on any XmlElement:
if (outEl.ParentNode != null) outEl.ParentNode.RemoveChild(outEl);
What are you trying to do with the code above? It doesn't relate to the question as far as I can see.
What is the problem with calling Remove on an XmlElement (which is an XmlNode)?
As far as I can see, XmlNode doesn't have a Remove() method either. It does have a RemoveChild(XmlNode) method, and so does XmlElement. You should use RemoveChild of the parent element to remove the child element.
I have a simple function that's designed to copy a section of an xml document to another. I want to replace one node with the other so ReplaceChild seems like the logical choice. I keep getting the error 'The reference node is not a child of this node.' though. That seems odd since I found that node by asking for the parent in the first place. Any idea what I'm doing wrong?
private static void KeepSection(XmlDocument newDoc, XmlDocument currentDoc, XmlNamespaceManager nsmgr, string path)
{
XmlNode section = currentDoc.SelectSingleNode(path, nsmgr);
XmlNode newSection = newDoc.SelectSingleNode(path, nsmgr);
if (newSection != null && section != null)
{
XmlNode parent = newSection.ParentNode;
parent.ReplaceChild(newSection, newDoc.ImportNode(section, true));
}
}
It looks like you have your ReplaceChild parameters reversed:
public virtual XmlNode ReplaceChild(
XmlNode newChild,
XmlNode oldChild
)
Actually I was being an idiot. I got the parameters to ReplaceChild the wrong way around. The code should have been,
parent.ReplaceChild(newDoc.ImportNode(section, true), newSection);
Sorry about that!