Get Child Nodes from an XML File - c#

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.

Related

Failing to read value XML attribute in C#

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

Renaming Xml node

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.

Selecting value from first xml child node

I have an XML file that contains multiple URLs for different image file sizes, and I'm trying to get a single url to load into a picture box. My issue is that the child nodes are named similarly, and the parent nodes are named similarly as well. For example, I want to pull the first medium image (ending in SL160_.jpg). See below for XML code
<Items>
<SmallImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL._SL75_.jpg</URL>
</SmallImage>
<MediumImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL._SL160_.jpg</URL>
</MediumImage>
<LargeImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL.jpg</URL>
</LargeImage>
<MediumImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL._SL162_.jpg</URL>
</MediumImage>
<LargeImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL.jpg</URL>
</LargeImage>
</Items>
I've tried using GetElementsByTag, as well as trying to call something like doc.SelectSingleNode("LargeImage").SelectSingleNode("URL").InnerText, and GetElementByID. All of these have given me an Object set to null reference exception.
What can I do to specify that I want the url from the first found MediumImage node?
Use LinqToXMLïĵŒIt is rather simple
string xml = #"<Items>
<SmallImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL._SL75_.jpg</URL>
</SmallImage>
<MediumImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL.01_SL160_.jpg</URL>
</MediumImage>
<LargeImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL.jpg</URL>
</LargeImage>
<MediumImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL.02_SL162_.jpg</URL>
</MediumImage>
<LargeImage>
<URL>http://ecx.images-amazon.com/images/I/51TAL%2Bn7AqL.jpg</URL>
</LargeImage>
</Items>";
XElement root = XElement.Parse(xml);
var ele = root.Elements("MediumImage").Where(e => e.Element("URL").Value.EndsWith("SL160_.jpg")).FirstOrDefault();
Console.WriteLine(ele);
In addition to Sky Fang's answer, I think the OP wants this:
var firstMedImg = root.Elements("MediumImage").First();
var imgUrl = firstMedImg.Element("URL").Value;
XmlDocument doc = new XmlDocument();
// PATH TO YOUR DOCUMENT
doc.Load("daco.xml");
// Select LIST ALL ELEMENTS SmallImage,MediumImage,LargeImage
XmlNodeList listOfAllImageElements = doc.SelectNodes("/Items/*");
foreach (XmlNode imageElement in listOfAllImageElements)
{
// Select URL ELEMENT
XmlNode urlElement= node.SelectSingleNode("URL");
System.Console.WriteLine(urlElement.InnerText);
}
Console.ReadLine();
If you want to select multiple url's
XmlDocument doc = new XmlDocument();
// PATH TO YOUR DOCUMENT
doc.Load("daco.xml");
// Select LIST ALL ELEMENTS SmallImage,MediumImage,LargeImage
XmlNodeList listOfAllImageElements = doc.SelectNodes("/Items/*");
foreach (XmlNode imageElement in listOfAllImageElements)
{
// Select URL's ELEMENTs
XmlNodeList listOfAllUrlElements = imageElement.SelectNodes("URL");
foreach (XmlNode urlElement in listOfAllUrlElements)
{
System.Console.WriteLine(urlElement.InnerText);
}
}
Console.ReadLine();
if you have specific namespace in your xml file
XmlDocument doc = new XmlDocument();
doc.Load("doc.xml");
XmlNamespaceManager man = new XmlNamespaceManager(doc.NameTable);
// reaplace http://schemas.microsoft.com/vs/2009/dgml with your namespace
man.AddNamespace("x", "http://schemas.microsoft.com/vs/2009/dgml");
// next you have to use x: in your path like this
XmlNodeList node = doc.SelectNodes("/x:Items/x:*, man);

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.

Remove all Artist node from an XML file

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.

Categories

Resources