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.
Related
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";
}
}
I have the following XML document structure.
<FareSearchResponse>
<AirlineList>
<AQR>...</AQR>
<ABA>...</ABA>
<AAI>...</AAI>
<A9W>...</A9W>
<AVS>...</AVS>
<AAF>...</AAF>
<AEY>...</AEY>
<ALH>...</ALH>
<AQF>...</AQF>
</AirlineList>
</FareSearchResponse>
I want to rename all child elements of AirlineList to Airline. The child name tags vary and can be any name. So there is no way of knowing which name tags will appear and what they will be. It is a dynamic XML document from a web service. So far I have managed to load the XML string into an XmlDocument;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(System.Web.HttpUtility.HtmlDecode(resultString));
XElement firstChild = xmlDoc.ToXDocument().Root.Elements().First();
I want to select all AirlineList elements and rename them to Airline.
I have added a more details. The XML document is now contained in firstChild. How do I replace elements in the firstChild and not directly from XmlDocument
Thanks.
I want to select all AirlineList elements and rename them to Airline.
Use Linq to Xml and update the Name for child elements.
var doc = XDocument.Load(filepath);
foreach (var element in doc.Descendants("AirlineList").Elements())
{
element.Name ="Airline";
}
Check this example
I have an XML File like below
<Attachment>
<FileName>Perimeter SRS.docx</FileName>
<FileSize>15572</FileSize>
<ActivityName>ActivityNamePerimeter SRS.docx</ActivityName>
<UserAlias>JameelM</UserAlias>
<DocumentTransferId>7123eb83-d768-4a58-be46-0dfaf1297b97</DocumentTransferId>
<EngagementName>EAuditEngagementNameNew</EngagementName>
<Sender>JameelM#orioninc.com</Sender>
</Attachment>
I read these xml file like below
var doc = new XmlDocument();
doc.Load(files);
foreach (XmlElement pointCoord in doc.SelectNodes("/Attachment"))
{
}
I need to get each child node value inside the Attachment node. How can i get these xml elements from the xml node list?
I need to get each child node value inside the Attachment node.
Your question is very unclear, but it looks like it's as simple as:
foreach (XmlNode node in doc.DocumentElement.ChildNodes)
{
}
After all, in the document you've shown us, the Attachment is the document element. No XPath is required.
As an aside, if you're using .NET 3.5 or higher, LINQ to XML is a much nicer XML API than the old DOM (XmlDocument etc) API.
try this
var data = from item in doc.Descendants("Attachment")
select new
{
FileName= item.Element("FileName").Value,
FileSize= item.Element("FileSize").Value,
Sender= item.Element("Sender").Value
};
foreach (var p in data)
Console.WriteLine(p.ToString());
var doc = new XmlDocument();
doc.Load(files);
foreach (XmlElement pointCoord in doc.SelectNodes("/Attachment"))
{
if(pointCoord!=null)
{
var valueOfElement=pointCoord.InnerText;
}
}
if you want to run conditional logic against the element names (UserAlias, etc) then use the Name property of the XmlElement.
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.
What's the difference using root node to select and using document object to select nodes?
Which way is preferred.
For example,
1.
XmlDocument Doc = new XmlDocument();
Doc.Load(mem);
XmlNodeList nodeList = Doc.SelectNodes(#"//#id");
2.
XmlDocument Doc = new XmlDocument();
Doc.Load(mem);
XmlElement root = Doc.DocumentElement;
XmlNodeList nodeList = root.SelectNodes(#"//#id");
In fact, I never got any differences. And use just
Doc.SelectNodes(#"//#id");
because if document's root exists
bool b = Doc.OuterXml == Doc.DocumentElement.OuterXml; // true
Since XPath's // expression always matches from the document root, the result will be the same whether you start from the document root or from its documentElement.
So I guess you're better off using the shorter Doc.SelectNodes("//#id"); syntax.
The root of an XML document contains its document element at least, but it may also contain processing instructions and comments. For instance, in this XML document:
<!-- This is a child of the root -->
<document_element>
<!-- This is a child of the document element -->
<document_element>
<!-- This is also a child of the root -->
the root has three child nodes, one of which is its top-level element. In this case, this:
XmlNodeList comments = doc.SelectNodes("comment()");
and this:
XmlNodeList comments = doc.DocumentElement.SelectNodes("comment()");
return totally different results.