Modify Child Node Value With C# XML Document Class - c#

I am a total noob, so apologies, but I have searched everywhere and I'm still stuck.
I am writing a program which will modify 2 XML docs after the user has selected an initial XML document and renamed it. Once the user changes the filename of the first XML (let's call it XML #1), the other two XML docs must have the new filename inserted into specific node values within them (XML #2 and #3).
Each XML doc has multiple "Asset" nodes with exactly the same names, and I need to distinguish the node I want by using a unique UUID value that is present in XML Doc #1.
For both XML #2 and #3, the "Id" nodes contain this same unique UUID. I am parsing XML#1 to get this UUID, and assigning it to a variable called "cpluuid."
Then I am searching XML #2 and #3 for nodes with an "Id" = to "cpluuid", and attempting to modify the correct node that contains the file name to be inserted.
XML Doc #2 - aka var = packing (additional "Asset" nodes omitted)
<Asset>
<Id>urn:uuid:d0686356-19c7-4bf4-b915-db778c308d1c</Id>
<AnnotationText>blah</AnnotationText>
<Hash>5Yf4BV4GZ4qE9EjvtohZ8Rq8M2w=</Hash>
<Size>21881</Size>
<Type>text/xml</Type>
<OriginalFileName>CPL_IMF_JOT_Sample_143.xml</OriginalFileName>
<HashAlgorithm Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
</Asset>
I have had success with updating XML Doc #2 in this manner. The "OriginalFileName" node was successfully updated to the variable value "cpluuid" via this code:
XmlDocument xmlDoc = new XmlDocument();
XmlNamespaceManager ns = new XmlNamespaceManager(xmlDoc.NameTable);
ns.AddNamespace("cplns1", "http://www.smpte-ra.org/schemas/2067-3/2016");
ns.AddNamespace("cplns2", "http://www.w3.org/2001/XMLSchema-instance");
ns.AddNamespace("pklns", "http://www.smpte-ra.org/schemas/2067-2/2016/PKL");
ns.AddNamespace("assetns", "http://www.smpte-ra.org/schemas/429-9/2007/AM");
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load(output);
string cpluuid = xmlDoc.SelectSingleNode("//cplns1:CompositionPlaylist/cplns1:Id", ns).InnerText;
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load(packing);
XmlNodeList nodeList;
XmlNode root = xmlDoc.DocumentElement;
nodeList = root.SelectNodes("descendant::pklns:Asset[pklns:Id=\"" + cpluuid + "\"]", ns);
foreach (XmlNode Asset in nodeList)
{
Asset["OriginalFileName"].InnerText = (outfile);
}
xmlDoc.PreserveWhitespace = true;
xmlDoc.Save(packing);
However, I am having trouble with XML doc #3, because the node I need to modify ("Path") is nested further down in the tree:
XML Doc #3 - aka var = assetmap
<Asset>
<Id>urn:uuid:d0686356-19c7-4bf4-b915-db778c308d1c</Id>
<ChunkList>
<Chunk>
<Path>CPL_IMF_JOT_Sample.xml</Path>
<VolumeIndex>1</VolumeIndex>
<Offset>0</Offset>
<Length>21881</Length>
</Chunk>
</ChunkList>
</Asset>
So I tried using similar code, but cannot figure out how to drill down further since "Path" is not a sibling of "Asset." This code does not modify the "Path" value. I tried using different XPath syntax, but nothing I know works:
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load(assetmap);
XmlNodeList nodeList2;
nodeList2 = root.SelectNodes("descendant::assetns:Asset[assetns:Id=\"" + cpluuid + "\"]", ns);
foreach (XmlNode Asset in nodeList2)
{
Asset["Path"].InnerText = (outfile);
}
xmlDoc.PreserveWhitespace = true;
xmlDoc.Save(assetmap);
I have tried various using System.Xml.Linq methods as well, but cannot get this to work.
UPDATE#1
Here is how I have been attempting to use XDocument. Seems like it should work, but always returns a Object Reference error.
var xml = XDocument.Load(assetmap);
var node = xml.Descendants("Asset").FirstOrDefault(asset => asset.Element("Id").Value == (cpluuid));
node.SetElementValue("Path", (outfile));
UPDATE #2
My second attempt using XDocument based on awesome feedback from #Juan M. Vergara. Unfortunately, while the code executes with no errors, the XML node does not update to the new value.
XDocument document = XDocument.Load(assetmap);
var assetElements = document.Elements("Asset");
foreach (var asset in assetElements)
{
var innerElements = asset.Elements("Id");
var matchingId = innerElements.FirstOrDefault(x => x.Value.Equals(cpluuid));
if (matchingId == null)
{
MessageBox.Show("UUID not found");
return;
}
var chunks = asset.Elements("ChunkList").First().Elements();
foreach (var chunk in chunks)
{
chunk.Elements("Path").First().SetValue(outfile);
}
}
document.Save(assetmap);
Here is a lager portion of the XML as well, in case there is an issue with namespaces or something else. The "Path" node that nneeds to be updated is the second one in the tree:
<?xml version="1.0" encoding="utf-8"?>
<AssetMap xmlns="http://www.smpte-ra.org/schemas/429-9/2007/AM">
<Id>urn:uuid:dc59ba55-adfd-4395-bdaa-de54202d014d</Id>
<Creator>Colorfront Transkoder 2017</Creator>
<VolumeCount>1</VolumeCount>
<IssueDate>2018-02-16T20:59:42-00:00</IssueDate>
<Issuer>Generic</Issuer>
<AssetList>
<Asset>
<Id>urn:uuid:296a656c-3610-4de1-9b08-2aa63245788d</Id>
<PackingList>true</PackingList>
<ChunkList>
<Chunk>
<Path>PKL_UUID.xml</Path>
<VolumeIndex>1</VolumeIndex>
<Offset>0</Offset>
<Length>3015</Length>
</Chunk>
</ChunkList>
</Asset>
<Asset>
<Id>urn:uuid:d0686356-19c7-4bf4-b915-db778c308d1c</Id>
<ChunkList>
<Chunk>
<Path>CPL_IMF_JOT_Sample.xml</Path>
<VolumeIndex>1</VolumeIndex>
<Offset>0</Offset>
<Length>21881</Length>
</Chunk>
</ChunkList>
</Asset>
</AssetList>
</AssetMap>
UPDATE #3
I'm trying the same method for XML#2 now, but it's not working. I assume because "OriginalFileName" is not the "First" element under "Asset." I'm trying different syntax combos, but nothing seems to work (sequence contains no element errors)
XDocument pkldoc = XDocument.Load(packing);
var pklns = pkldoc.Root.GetDefaultNamespace();
var packingList = pkldoc.Elements(pklns + "PackingList").First(); // this ignores the namespace
var pklassetList = packingList.Elements(pklns + "AssetList").First();
var pklassetElements = pklassetList.Elements(pklns + "Asset");
foreach (var pklasset in pklassetElements)
{
var innerElements = pklasset.Elements(pklns + "Id");
var matchingId = innerElements.FirstOrDefault(x => x.Value.Equals(cpluuid));
if (matchingId == null)
{
//MessageBox.Show("UUID not found");
continue;
}
var ofns = pklasset.Elements(pklns + "Asset").First().Elements();
foreach (var ofn in ofns)
{
ofn.Elements(pklns + "OriginalFileName").First().SetValue(outfile);
}
}
UPDATE #4
Here are the whole contents of XML #2. The structure is different than XML#3. I only want to update the "OriginalFileName" element in the very last "Asset" tree.
<?xml version="1.0" encoding="UTF-8"?>
<PackingList xmlns="http://www.smpte-ra.org/schemas/2067-2/2016/PKL">
<Id>urn:uuid:296a656c-3610-4de1-9b08-2aa63245788d</Id>
<AnnotationText>IMF_JOT_Sample</AnnotationText>
<IssueDate>2018-02-16T20:59:42-00:00</IssueDate>
<Issuer>Generic</Issuer>
<Creator>Generic</Creator>
<AssetList>
<Asset>
<Id>urn:uuid:744f36b7-fc7e-4179-8b75-c71c18f98156</Id>
<AnnotationText>Video_744f36b7-fc7e-4179-8b75-c71c18f98156.mxf</AnnotationText>
<Hash>8HhnKnLn+Lp/Ik9i94Ml4SXAxH4=</Hash>
<Size>14568486</Size>
<Type>application/mxf</Type>
<OriginalFileName>Video_744f36b7-fc7e-4179-8b75-c71c18f98156.mxf</OriginalFileName>
<HashAlgorithm Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
</Asset>
<Asset>
<Id>urn:uuid:bf5438ea-ba58-4ae0-a64a-5d23cee2ebb3</Id>
<AnnotationText>Audio_bf5438ea-ba58-4ae0-a64a-5d23cee2ebb3.mxf</AnnotationText>
<Hash>Wg4aEAE5Ji9e14ZyGkvfUUjBwCw=</Hash>
<Size>4341294</Size>
<Type>application/mxf</Type>
<OriginalFileName>Audio_bf5438ea-ba58-4ae0-a64a-5d23cee2ebb3.mxf</OriginalFileName>
<HashAlgorithm Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
</Asset>
<Asset>
<Id>urn:uuid:dd5a88d2-ccec-4b22-8584-fda51945c3ea</Id>
<AnnotationText>Audio_dd5a88d2-ccec-4b22-8584-fda51945c3ea.mxf</AnnotationText>
<Hash>OwjRFnWZCdKHSZ+3PBXroDhMMlY=</Hash>
<Size>1458414</Size>
<Type>application/mxf</Type>
<OriginalFileName>Audio_dd5a88d2-ccec-4b22-8584-fda51945c3ea.mxf</OriginalFileName>
<HashAlgorithm Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
</Asset>
<Asset>
<Id>urn:uuid:9e11458a-71fb-4702-8609-55d2308dcc64</Id>
<AnnotationText>Sub_9e11458a-71fb-4702-8609-55d2308dcc64.mxf</AnnotationText>
<Hash>48KyxgwCJVXIdgAGfaNApheQN5M=</Hash>
<Size>34509</Size>
<Type>application/mxf</Type>
<OriginalFileName>Sub_9e11458a-71fb-4702-8609-55d2308dcc64.mxf</OriginalFileName>
<HashAlgorithm Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
</Asset>
<Asset>
<Id>urn:uuid:3f57f474-4c81-438e-a67d-1b08fa09a10d</Id>
<AnnotationText>IMF_JOT_Sample</AnnotationText>
<Hash>q8TiPkg/3devlN3LXnBhrgkZ968=</Hash>
<Size>713</Size>
<Type>text/xml</Type>
<OriginalFileName>OPL_3f57f474-4c81-438e-a67d-1b08fa09a10d.xml</OriginalFileName>
<HashAlgorithm Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
</Asset>
<Asset>
<Id>urn:uuid:d0686356-19c7-4bf4-b915-db778c308d1c</Id>
<AnnotationText>CPL_IMF_JOT_Sample.xml</AnnotationText>
<Hash>5Yf4BV4GZ4qE9EjvtohZ8Rq8M2w=</Hash>
<Size>21881</Size>
<Type>text/xml</Type>
<OriginalFileName>CPL_IMF_JOT_Sample.xml</OriginalFileName>
<HashAlgorithm Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
</Asset>
UPDATE #5
Thanks again Juan for your help. Here is the working solution for XML Doc #2. I know it's not very pretty, but it works.
At some point I'd like to go back and fully digest your last example and combine / cleanup my code the way you have. THANKS!
XDocument pkldoc = XDocument.Load(packing);
var pklns = pkldoc.Root.GetDefaultNamespace();
var pklassetElements = pkldoc.Descendants(pklns + "Asset");
foreach (var pklasset in pklassetElements)
{
var idElement = pklasset.Descendants(pklns + "Id").First();
if (!idElement.Value.Equals(cpluuid))
continue;
SetNewValue(pklasset, pklns + "OriginalFileName", outfile);
}
void SetNewValue(XElement currentElement, XName elementName, string newValue)
{
var matchingElements = currentElement.Descendants(elementName);
if (matchingElements.Any())
{
foreach (var element in matchingElements)
element.SetValue(newValue);
}
}
pkldoc.Save(packing);

I preferred to write a different answer, due to the new conditions.
Given you have those 2 sample xmls, with different structures but with common nodes, I have given another try using Descendants.
You basically need to find the Asset elements, then check whether the Id matches, and if so, update the Path or OriginalFileName element, try this code:
private void Run()
{
XDocument doc1 = XDocument.Load("xml1.xml");
XDocument doc2 = XDocument.Load("xml2.xml");
var id = #"urn:uuid:d0686356-19c7-4bf4-b915-db778c308d1c";
ReplaceId(doc1, id, "new path");
ReplaceId(doc2, id, "new path");
doc1.Save("xml1_new.xml");
doc2.Save("xml2_new.xml");
Console.WriteLine("Enter to exit...");
Console.ReadLine();
}
private void ReplaceId(XDocument doc, string id, string newValue)
{
var ns = doc.Root.GetDefaultNamespace();
var assetElements = doc.Descendants(ns + "Asset");
foreach (var element in assetElements)
{
var idElement = element.Descendants(ns + "Id").First();
if (!idElement.Value.Equals(id))
continue;
// for xml model #1
SetNewValue(element, ns + "Path", newValue);
// for xml model #2
SetNewValue(element, ns + "OriginalFileName", newValue);
}
}
private void SetNewValue(XElement currentElement, XName elementName, string newValue)
{
var matchingElements = currentElement.Descendants(elementName);
if (matchingElements.Any())
{
foreach (var element in matchingElements)
element.SetValue(newValue);
}
}
Let me now how it goes with this one.
UPDATE
A modification to ReplaceId to know if a replacement has been done:
private bool ReplaceId(XDocument doc, string id, string newValue)
{
var ns = doc.Root.GetDefaultNamespace();
var assetElements = doc.Descendants(ns + "Asset");
var result = false;
foreach (var element in assetElements)
{
var idElement = element.Descendants(ns + "Id").First();
if (!idElement.Value.Equals(id))
continue;
// for xml model #1
SetNewValue(element, ns + "Path", newValue);
// for xml model #2
SetNewValue(element, ns + "OriginalFileName", newValue);
result = true;
}
return result;
}

I just gave it a try and put together some code in a console application example, bear in mind that I do not control all errors in al cases (like element not found...), but I think that it can give you an idea of how you can use System.Xml.Linq.
Hope it helps.
using System;
using System.Linq;
using System.Xml.Linq;
namespace ParsingXML
{
class Program
{
const string _xml =
#"<Asset>
<Id>urn:uuid:d0686356-19c7-4bf4-b915-db778c308d1c</Id>
<ChunkList>
<Chunk>
<Path>CPL_IMF_JOT_Sample.xml</Path>
<VolumeIndex>1</VolumeIndex>
<Offset>0</Offset>
<Length>21881</Length>
</Chunk>
</ChunkList>
</Asset>";
static void Main(string[] args)
{
ReplacePath(
#"urn:uuid:d0686356-19c7-4bf4-b915-db778c308d1c",
#"c:\path\to\somefilename.xml"
);
Console.WriteLine("Enter to exit...");
Console.ReadLine();
}
static void ReplacePath(string id, string pathToSet)
{
XDocument document = XDocument.Parse(_xml);
var assetElements = document.Elements("Asset");
foreach (var asset in assetElements)
{
var innerElements = asset.Elements("Id");
var matchingId = innerElements.FirstOrDefault(e => e.Value.Equals(id));
if (matchingId == null)
{
Console.WriteLine("id not found");
return;
}
var chunks = asset.Elements("ChunkList").First().Elements();
foreach (var chunk in chunks)
{
chunk.Elements("Path").First().SetValue(pathToSet);
}
}
var xml = document.ToString();
Console.WriteLine(xml);
Console.WriteLine("Enter to exit...");
Console.ReadLine();
}
}
}
And this is the output I get:
<Asset>
<Id>urn:uuid:d0686356-19c7-4bf4-b915-db778c308d1c</Id>
<ChunkList>
<Chunk>
<Path>c:\path\to\somefilename.xml</Path>
<VolumeIndex>1</VolumeIndex>
<Offset>0</Offset>
<Length>21881</Length>
</Chunk>
</ChunkList>
</Asset>
Enter to exit...
Update
Problem is that there are more than one Asset, and as the first one is not matching the first foreach gives a message and stops execution in the return, just replace the return statement by a continue instruction, so the execution does not stop.
In the other hand, you may have to include tha namespace, this is the updated code of my initial ReplacePath function:
static void ReplacePath(string targetFile, string id, string outfile)
{
//XDocument document = XDocument.Parse(_xml);
XDocument document = XDocument.Load(targetFile);
// get root namespace to use with rest of element names
var ns = document.Root.GetDefaultNamespace();
var assetMap = document.Elements(ns + "AssetMap").First(); // this ignores the namespace
var assetList = assetMap.Elements(ns + "AssetList").First();
var assetElements = assetList.Elements(ns + "Asset");
foreach (var asset in assetElements)
{
var innerElements = asset.Elements(ns + "Id");
var matchingId = innerElements.FirstOrDefault(e => e.Value.Equals(id));
if (matchingId == null)
{
continue;
}
var chunks = asset.Elements(ns + "ChunkList").First().Elements();
foreach (var chunk in chunks)
{
var chunkElement = chunk.Elements(ns + "Path").First();
chunkElement.SetValue(outfile);
}
}
var xml = document.ToString();
Console.WriteLine(xml);
Console.WriteLine("writing to file");
document.Save(targetFile);
Console.WriteLine("Enter to exit...");
Console.ReadLine();
}
I hope this time you got the right answer :).

Related

Loop through XML with XmlDocument

I'm new to using Linq and XMLDocument.
I have a simple XML file and I want to loop through all of the elements and print the tag and value. I don't want to use the XML Tags when looping through. this is what I have so far.
XML file:
<?xml version="1.0" encoding="UTF-8"?>
<Step1>One
<Step2>Two
<Step3>Three
<Step4>Four
</Step4>
</Step3>
</Step2>
</Step1>
C# Code
private void StartIt()
{
System.Xml.XmlDocument xd = new System.Xml.XmlDocument();
xd.Load(#"C:\Projects\GetXML\testLayers.xml");
XmlNodeList nl = xd.SelectNodes("Layer1");
foreach (XmlNode xnode in nl)
{
Console.WriteLine(xnode.Name + " = " + xnode.InnerText); // + " " + xnode.InnerXml);
}
}
Results:
Step1 = One
Two
Three
Four
What I want:
Step1 = One
Step2 = Two
Step3 = Three
Step4 = Four
Any suggestions?
With a little help of Linq,
XmlDocument doc = new XmlDocument();
doc.Load(fname);
var nodes = doc.SelectNodes("//*[text()]")
.Cast<XmlNode>()
.Select(n => new {
Name= n.Name,
Value = n.SelectSingleNode("text()").Value
})
.ToList();
// System.Xml.XmlDocument version
XmlDocument xd = new XmlDocument();
xd.Load(#"C:\Projects\GetXML\testLayers.xml");
foreach (XmlElement step in xd.SelectNodes("//*"))
{
Console.WriteLine("{0} = {1}", step.Name,
step.SelectSingleNode("text()").Value);
}
// System.Xml.Linq.XDocument version
XDocument xdLinq = XDocument.Load(#"C:\Projects\GetXML\testLayers.xml");
foreach (XElement step in xdLinq.XPathSelectElements("//*"))
{
Console.WriteLine("{0} = {1}", step.Name,
step.Nodes().Where(n => n.NodeType == XmlNodeType.Text).FirstOrDefault());
}
You can do the same using LINQ to XML and XDocument class:
var xDoc = XDocument.Load("Input.txt");
foreach (var e in xDoc.Descendants())
{
Console.WriteLine("{0} = {1}", e.Name, e.Nodes().OfType<XText>().First().Value.Trim());
}

How I get the parentnode attribute name if I have the attribute name of the child node?

hi i want to get the up node from a xml. For example here a xml structure...
<feature name="mod1">
<user name="user1"></user>
<user name="user2"></user>
<user name="user3"></user>
</feature>
i have in my application the username and i want than the node feature name attribute.
XmlReader reader = XmlReader.Create(new StringReader(xml));
XElement doc = XElement.Load(reader);
int counter = 0;
foreach (XElement user in doc.Descendants("USER"))
{
try
{
row = tb.NewRow();
row["ID"] = counter++;
row["Name"] = user.Attribute("NAME").Value;
row["Host"] = user.Attribute("HOST").Value;
row["Used_Licenses"] = user.Attribute("USED_LICENSES").Value;
row["Checkout_Time"] = user.Attribute("CHECKOUT_TIME").Value;
row["Modul"] = user.Parent.Attribute("NAME").Value; //don't work :(
tb.Rows.Add(row);
}
catch (Exception)
{
}
}
you should be able to get it by
user.Parent.Attribute("NAME").Value;
this Works with :
<LM-X STAT_VERSION="3.32">
<LICENSE_PATH >
<FEATURE NAME="GlobalZoneEU" >
<USER NAME="SYSTEM" HOST="LRV171" IP="172.16.11.115" USED_LICENSES="2000" LOGIN_TIME="2013-04-17 12:42" CHECKOUT_TIME="2013-04-17 12:42" SHARE_CUSTOM="hweuser:172.16.11.115"/>
<USER NAME="pbsadmin" HOST="SERV11" IP="172.16.11.115" USED_LICENSES="720" LOGIN_TIME="2013-04-17 12:44" CHECKOUT_TIME="2013-04-17 12:44" SHARE_CUSTOM="pbsadmin:LWSERV171:1592_40960072_1356792762_826820"/>
</FEATURE>
</LICENSE_PATH>
</LM-X>
EDIT
Get the feature name by user name :
var featureNames = xDoc.Descendants("USER")
.Where(x => x.Attribute("NAME").Value == <your input>)
.Select(x => x.Parent.Attribute("NAME").Value);
var firstFeatureName = featureNames.FirstOrDefault();
Seems like the attributes are case sensitive.
XmlReader reader = XmlReader.Create(\\File Path);
XElement doc = XElement.Load(reader);
int counter = 0;
foreach (XElement user in doc.Descendants("USER"))
{
try
{
string node = user.Parent.Attribute("NAME").Value; //Working - Returning 'GlobalZoneEU'
}
catch (Exception)
{
}
}
The following code should work for you.
string xml = "<feature name=\"mod1\">";
xml += "<user name=\"user1\"> </user>";
xml += "<user name=\"user2\"> </user> ";
xml += "<user name=\"user3\"></user>";
xml += "</feature>";
XmlDocument xdoc=new XmlDocument();
xdoc.LoadXml(xml);
XDocument mydoc = XDocument.Parse(xdoc.OuterXml);
var result = mydoc.Elements("feature").Where(parent =>
parent.Elements("user").Any(child =>
child.Attribute("name").Value == "user2"));
and don't forget to include
using System.Xml;
using System.Xml.Linq;

How to update the XMLDocument using c#?

I want to update the xml document and i need to return the updated xml in string. I am trying like below. when i save the document it expects the file name. but i dont want to save this as file. i just want to get the updated xml in string.
string OldXml = #"<Root>
<Childs>
<first>this is first</first>
<second>this is second </second>
</Childs
</Root>";
XmlDocument NewXml = new XmlDocument();
NewXml.LoadXml(OldXml );
XmlNode root = NewXml.DocumentElement;
XmlNodeList allnodes = root.SelectNodes("*");
foreach (XmlNode eachnode in allnodes)
{
if (eachnode.Name == "first")
{
eachnode.InnerText = "1";
}
}
NewXml.Save();
string newxml = NewXml.OuterXml;
You don't need to call Save method because string is immutable, your problem is in root.SelectNodes("*"), it just get child nodes, not all level of nodes. You need to go one more level:
foreach (XmlNode eachnode in allnodes)
{
var firstNode = eachnode.ChildNodes.Cast<XmlNode>()
.SingleOrDefault(node => node.Name == "first");
if (firstNode != null)
{
firstNode.InnerText = "1";
}
}
string newxml = NewXml.OuterXml;
It would be strongly recommended using LINQ to XML, it's simpler:
var xDoc = XDocument.Parse(OldXml);
foreach (var element in xDoc.Descendants("first"))
element.SetValue(1);
string newXml = xDoc.ToString();
Your iteration never reaches a node called "first". Else it would work fine without saving the NewXml.
You could however use a XElement and iterate over all descendants.
string OldXml = #"<Root>
<Childs>
<first>this is first</first>
<second>this is second </second>
</Childs>
</Root>";
var NewXml = XElement.Parse(OldXml);
foreach (var node in NewXml.Descendants())
{
if (node.Name.LocalName == "first")
{
node.Value = "1";
}
}
var reader = NewXml.CreateReader();
reader.MoveToContent();
string newxml = reader.ReadInnerXml();

How can I get all text nodes from XML file

I want to get all text nodes from an XML file.
How can I do this?
Example Input:
<root>
<slide>
<Image>hi</Image>
<ImageContent>this</ImageContent>
<Thumbnail>is</Thumbnail>
<ThumbnailContent>A</ThumbnailContent>
</slide>
</root>
Expected Output:
hi this is A
The only solution (so far) to enumerate all text nodes in any xml, regardless of its structure:
string input = #"
<root>
<slide>
<Image>hi</Image>
<ImageContent>this</ImageContent>
<Thumbnail>is</Thumbnail>
<ThumbnailContent>A</ThumbnailContent>
</slide>
</root>";
foreach (XText text in (IEnumerable)XDocument.Parse(input).XPathEvaluate("//*/text()"))
{
Console.WriteLine(text.Value);
}
EDIT: if you want to load xml from file then use XDocument.Load instead.
This code will print the inner text of all xml nodes which doesnt have a child:
static void Main(string[] args)
{
XmlDocument x = new XmlDocument();
x.Load("exp.xml");
PrintNode(x.DocumentElement);
}
private static void PrintNode(XmlNode x)
{
if (!x.HasChildNodes)
Console.Write(string.Format("{0} ", x.InnerText));
for (int i = 0; i < x.ChildNodes.Count; i++)
{
PrintNode(x.ChildNodes[i]);
}
}
On your example XML it will result in the output you want :)
You can try this:
string input = #"
<root>
<slide>
<Image>hi</Image>
<ImageContent>this</ImageContent>
<Thumbnail>is</Thumbnail>
<ThumbnailContent>A</ThumbnailContent>
</slide>
</root>";
XDocument doc = XDocument.Parse(input);
//You can also load data from file by passing file path to Load method
//XDocument doc = XDocument.Load("Data.xml");
foreach(var slide in doc.Root.Elements("slide"))
{
var words = slide.Elements().Select(el => el.Value);
string s = String.Join(" ", words.ToArray());
}
This will work
static void Main(string[] args)
{
XDocument xmlSkuDescDoc = XDocument.Parse
(#"<root>
<slide>
<Image>hi</Image>
<ImageContent>this</ImageContent>
<Thumbnail>is</Thumbnail>
<ThumbnailContent>A</ThumbnailContent>
</slide>
</root> "
);
var result = (from data in xmlSkuDescDoc.Descendants("slide")
select data).Elements().Select(i => i.Value).Aggregate((a, b) => a + " " + b);
Console.ReadKey();
}
N.B.~ use XDocument.Load(filename) if loading from file
e.g.
string fileName = #"D:\MyXml.xml";
XDocument xmlSkuDescDoc = XDocument.Load(filename);
.... and the rest follows as shown above
It can be done using XDocument class (LINQ to XML). Assuming that you have exactly one slide element:
Using plain XDocument navigation:
var doc = XDocument.Load("file path here");
if (doc.Root == null)
throw new ArgumentException(); // No root node!
var slideElement = doc.Root.Element("slide");
if (slideElement == null)
throw new ArgumentException(); // No slide node!
var values = string.Join(" ", slideElement.Elements().Select(element => element.Value));
Using XPath node selection:
var doc = XDocument.Load("file path here");
var slideElements = doc.XPathSelectElements("root/slide/*");
var values = string.Join(" ", slideElements.Select(element => element.Value));

how to determine count of tag

I have a bit of xml file named Sample.xml which is shown below
<?xml version="1.0" encoding="ISO-8859-1"?>
<countries>
<country>
<text>Norway</text>
<value>N</value>
</country>
<country>
<text>Sweden</text>
<value>S</value>
</country>
<country>
<text>France</text>
<value>F</value>
</country>
<country>
<text>Italy</text>
<value>I</value>
</country>
</countries>
i have button named submit(button1).If i click that button i need to display the count(PartitionName="AIX") in a text box named textBox1, means How many PartitionName="AIX" is belonging to Type="NIC"
Can any one give me the c# code
I did like this,,but not able to get the answaer
private void button1_Click(object sender, EventArgs e)
{
XmlDocument doc1 = new XmlDocument();
doc1.Load(#"D:\New Folder\WindowsFormsApplication3\WindowsFormsApplication3\Sample.xml");
XmlNodeList a = doc1.GetElementsByTagName("AIX");
textBox1.Text = a.Count.ToString();
}
here is a quick soln I arrived at using linq. hope you find it useful.
static void Main(string[] args)
{
XElement xElement = XElement.Load(#"C:\Labs\test.xml");
// PartitionName="AIX" is belonging to Type="NIC"
var count = xElement.Descendants().Where(x => x.Name.ToString().Contains("Port")) // namespaces might be used here for faster traversal..
.Where(x => x.HasAttributes && x.Attribute("Type").Value == "NIC")
.Descendants().Where(x => x.Name.ToString().Contains("Client"))
.Where(x => x.Attribute("PartitionName").Value == "AIX").Count();
string str = count.ToString();
Console.WriteLine("Count = {0}", str);
Console.ReadLine();
}
Using xpath something like this:
count(vendor/Slot/Port[#Type='NIC']/Client[#PartitionName='AIX'])
But you have to modify it to support your namespaces.
Also easier and shorter code than going the Linq route for this particular case.
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
nsMgr.AddNamespace("inv", "http://secon.com/Ultravendor");
int count = doc.SelectNodes("inv:vendor/inv:Slot/inv:Port[#Type='NIC']/inv:Client[#PartitionName='AIX']", nsMgr).Count;
XmlDocument doc1 = new XmlDocument();
doc1.Load(#"C:\Labs\test.xml");
XmlNodeList nodes = doc1.GetElementsByTagName("inv:Port");
int count = 0;
foreach (XmlNode childNode in nodes)
{
XmlNodeReader nodeReader = new XmlNodeReader(childNode);
while (nodeReader.Read())
{
if (nodeReader.GetAttribute("PartitionName") == "AIX")
{
count++;
}
}
}
Console.WriteLine("Count = {0}", count);
Console.ReadLine();

Categories

Resources