My XML looks like this. I want to get "NGSPkgTrackingId"
I have to walk Node->Node->Attribute.
I need some help
<TrackingID>{06EB4234-8A65-4C28-AD45-DAC87B972437}</TrackingID>
<Documents>
<Details Weight="1.7950" ZIP="04011" ZIPPlus4="3103" >
<Identifier Qualifier="eVSBarcode" Value="4200401192458927004050120118829995" />
<Identifier Qualifier="REFERENCENUM" Value="301113159600798" />
<Identifier Qualifier="NGSPkgTrackingId" Value="00983482428">
</Details>
<Details Weight="3.3450" ZIP="04011" CountryCode="US" >
< Identifier Qualifier="eVSBarcode" Value="4200401192612927004646230017808858" />
<Identifier Qualifier="REFERENCENUM" Value="117913788" /> Default="true" />
</Details>
Thank you
Try looking up the msdn documentation on XmlDocument. As har07 pointed out, you can use SelectSingleNode(). Which you can reference here.
As for what the code could look like, assuming you just want to find the value associated with a given Identifier Qualifier, it could work like this:
public static string FindValue(string qualifier, string xml)
{
var value = string.Empty;
XmlDocument doc = new XmlDocument();
doc.Load(xml);
XmlNode root = doc.DocumentElement;
XmlNode identifier = root.SelectSingleNode(#"descendant::Details/Identifier [#Qualifier='" + qualifier +"']");
value = identifier.Attributes["Value"].Value;
return value;
}
We should be doing null reference checks, so I'll add them in
public static string FindValue(string qualifier, string xml)
{
var value = string.Empty;
XmlDocument doc = new XmlDocument();
doc.Load(xml);
XmlNode identifier = null;
XmlNode root = doc.DocumentElement;
if (root != null)
identifier = root.SelectSingleNode(#"descendant::Details/Identifier [#Qualifier='" + qualifier +"']");
if (identifier?.Attributes != null) value = identifier.Attributes["Value"].Value;
return value;
}
Assuming you have a valid xml like this
<?xml version="1.0" encoding="utf-8" ?>
<Documents>
<Details Weight="1.7950" ZIP="04011" ZIPPlus4="3103" >
<Identifier Qualifier="eVSBarcode" Value="4200401192458927004050120118829995" />
<Identifier Qualifier="REFERENCENUM" Value="301113159600798" />
<Identifier Qualifier="NGSPkgTrackingId" Value="00983482428"/>
</Details>
<Details Weight="3.3450" ZIP="04011" CountryCode="US">
<Identifier Qualifier="eVSBarcode" Value="4200401192612927004646230017808858" />
<Identifier Qualifier="REFERENCENUM" Value="117913788" /> Default="true" />
</Details>
</Documents>
Accessing the value "NGSPkgTrackingId" should be pretty straightforward using the below code
XmlDocument xmlDoc = new XmlDocument();
XmlReader reader = XmlReader.Create("C:/Users/.../documents.xml ");
xmlDoc.Load(reader);
XmlNodeList nodeList = xmlDoc.SelectNodes("/Documents").Item(0).ChildNodes;
string val = xmlDoc.DocumentElement.ChildNodes[0].LastChild.Attributes.Item(0).Value;
Console.WriteLine(val);
Alternatively, you can use selectNodes
var node2 =xmlDoc.DocumentElement.SelectNodes(".//Details/Identifier");
var ans1= node2.Item(2).Attributes["Qualifier"].Value;
Console.WriteLine(ans1);
Third Option
var value= xmlDoc.DocumentElement.SelectSingleNode("descendant::Details").LastChild.Attributes["Qualifier"].Value;
Console.WriteLine(value);
Related
Please how can I get value of attribute Value of element StatusCode in this XML:
<LogoutResponse
ID="_f525259e-7e91-4282-9dc3-a0da65a4a17a"
Version="2.0"
IssueInstant="2021-05-17T15:41:55Z"
InResponseTo="_5089729f-5cc0-4a66-a3c1-e710cde92897"
Destination="https://idp.xyz/logout.aspx"
xmlns="urn:oasis:names:tc:SAML:2.0:protocol">
<Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">https://abc.xyz/api</Issuer>
<Status>
<StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
</Status>
</LogoutResponse>
Due to the namespaces, this gets a little messy:
var doc = new XmlDocument();
doc.LoadXml(#"<LogoutResponse
ID=""_f525259e-7e91-4282-9dc3-a0da65a4a17a""
Version=""2.0""
IssueInstant=""2021-05-17T15:41:55Z""
InResponseTo=""_5089729f-5cc0-4a66-a3c1-e710cde92897""
Destination=""https://idp.xyz/logout.aspx""
xmlns=""urn:oasis:names:tc:SAML:2.0:protocol"">
<Issuer xmlns=""urn:oasis:names:tc:SAML:2.0:assertion"">https://abc.xyz/api</Issuer>
<Status>
<StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Success"" />
</Status>
</LogoutResponse>");
var ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("oasis", "urn:oasis:names:tc:SAML:2.0:protocol");
var attr = (XmlAttribute)doc.SelectSingleNode(
"/oasis:LogoutResponse/oasis:Status/oasis:StatusCode/#Value", ns);
System.Console.WriteLine(attr.Value);
You can try with XmlDocument.
Note: since you have a name space (xmlns ...) all elements in your xml
by default in name space. hence you are getting object reference
error. I have updated the code and .netfiddle. please have a look
var xml = #"<LogoutResponse
ID=""_f525259e-7e91-4282-9dc3-a0da65a4a17a""
Version=""2.0""
IssueInstant=""2021-05-17T15:41:55Z""
InResponseTo=""_5089729f-5cc0-4a66-a3c1-e710cde92897""
Destination=""https://idp.xyz/logout.aspx""
xmlns=""urn:oasis:names:tc:SAML:2.0:protocol"">
<Issuer xmlns=""urn:oasis:names:tc:SAML:2.0:assertion"">https://abc.xyz/api</Issuer>
<Status>
<StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Success"" />
</Status>
</LogoutResponse>";
var doc = new System.Xml.XmlDocument();
doc.LoadXml(xml);
var nsManager = new XmlNamespaceManager(doc.NameTable);
nsManager.AddNamespace("ns", "urn:oasis:names:tc:SAML:2.0:protocol");
var result = doc.SelectSingleNode("/ns:LogoutResponse/ns:Status/ns:StatusCode/#Value", nsManager).InnerText;
Console.WriteLine(result);
By using LINQ to XML API.
It is available in the .Net Framework since 2007.
c#
void Main()
{
XDocument xdoc = XDocument.Parse(#"<LogoutResponse xmlns='urn:oasis:names:tc:SAML:2.0:protocol'
Destination='https://idp.xyz/logout.aspx' ID='_f525259e-7e91-4282-9dc3-a0da65a4a17a'
InResponseTo='_5089729f-5cc0-4a66-a3c1-e710cde92897' IssueInstant='2021-05-17T15:41:55Z' Version='2.0'>
<Issuer xmlns='urn:oasis:names:tc:SAML:2.0:assertion'>https://abc.xyz/api</Issuer>
<Status>
<StatusCode Value='urn:oasis:names:tc:SAML:2.0:status:Success'></StatusCode>
</Status>
</LogoutResponse>");
XNamespace ns1 = "urn:oasis:names:tc:SAML:2.0:protocol";
string StatusCodeValue = xdoc.Descendants(ns1 + "StatusCode")
.Attributes("Value")
.FirstOrDefault()?.Value;
Console.WriteLine("StatusCodeValue='{0}'", StatusCodeValue);
}
Output
StatusCodeValue='urn:oasis:names:tc:SAML:2.0:status:Success'
I need to figure out how to turn one XML record with sub nodes into multiple records using C#. Yes, I know it would be easier to do this using XSLT but that isn't an option. I have an XML file that must be modified to be used by 5 different uses so I need a common starting point.
Forgive my lack of understanding but nothing I can find seems to go in this direction. Everything goes in the other direction. Here is a sample of my code and file.
The source file.
<inventoryitems>
<inventoryitem>
<id>11101</id>
<displayname>LG HAMBURGER PATTY</displayname>
<basemeasure>EACH</basemeasure>
<reportingmeasure>EACH</reportingmeasure>
<measures>
<measure>
<name>CS</name>
<factor>1.000000</factor>
<isactive>1</isactive>
</measure>
<measure>
<name>ST</name>
<factor>8.000000</factor>
<isactive>1</isactive>
</measure>
<measure>
<name>EACH</name>
<factor>120.000000</factor>
<isactive>1</isactive>
</measure>
</measures>
<categories>
<category>
<name>MEATS</name>
</category>
</categories>
<locations />
<skus />
</inventoryitem>
<inventoryitem>
<id>11102</id>
<displayname>SM HAMBURGER PATTY</displayname>
<basemeasure>EACH</basemeasure>
<reportingmeasure>EACH</reportingmeasure>
<measures>
<measure>
<name>ST</name>
<factor>6.000000</factor>
<isactive>1</isactive>
</measure>
<measure>
<name>CS</name>
<factor>1.000000</factor>
<isactive>1</isactive>
</measure>
<measure>
<name>EACH</name>
<factor>96.000000</factor>
<isactive>1</isactive>
</measure>
</measures>
<categories>
<category>
<name>MEATS</name>
</category>
</categories>
<locations />
<skus />
</inventoryitem>
<inventoryitem>
<id>11202</id>
<displayname>BREAD SM BUN 4</displayname>
<basemeasure>EACH</basemeasure>
<reportingmeasure>EACH</reportingmeasure>
<measures>
<measure>
<name>TR</name>
<factor>1.000000</factor>
<isactive>1</isactive>
</measure>
<measure>
<name>EACH</name>
<factor>30.000000</factor>
<isactive>1</isactive>
</measure>
</measures>
<categories>
<category>
<name>BAKERY</name>
</category>
</categories>
<locations />
<skus />
</inventoryitem>
</inventoryitems>
What I need to get would look something like this.
<data>
<row InventoryItemId="11201" ItemDescription="BREAD LG BUN 5" CategoryName="BAKERY" Measure="TR" />
<row InventoryItemId="11201" ItemDescription="BREAD LG BUN 5" CategoryName="BAKERY" Measure="EACH" />
</data>
I was able to write the code to mode the value to an attribute when the is only one node but I am at a loss on what to do when there is a sub node with multiple values.
invlist = results.Substring(results.IndexOf("<inventoryitems>"), (results.IndexOf("</inventoryitemsresponsedata>") - results.IndexOf("<inventoryitems>")));
XmlDocument doc = new XmlDocument();
XmlNode nd = doc.CreateNode("element", "data", "");
doc.AppendChild(nd);
//XmlNode rw = doc.CreateNode("element", "row", "");
//nd.AppendChild(rw);
var invitems = new XmlDocument { InnerXml = invlist };
XmlNode result = doc.ImportNode(invitems.DocumentElement, true);
nd.AppendChild(result);
XmlNodeList ndList = doc.SelectNodes("data/inventoryitems/inventoryitem");
foreach (XmlNode id in ndList)
{
XmlNode idnode = id.SelectSingleNode("id");
if (idnode != null)
{
XmlNode rw = doc.CreateNode("element", "row", "");
nd.AppendChild(rw);
var attribute = doc.CreateAttribute("InventoryItemId");
attribute.Value = idnode.InnerXml;
var Description = doc.CreateAttribute("ItemDescription");
Description.Value = id.SelectSingleNode("displayname").InnerXml;
rw.Attributes.Append(attribute);
rw.Attributes.Append(Description);
}
XmlNodeList msList = id.SelectNodes("measures/measure");
foreach (XmlNode mes in msList)
{
XmlNode msnode = mes.SelectSingleNode("name");
if (msnode != null)
{
var attribute = doc.CreateAttribute("Measure");
attribute.Value = msnode.InnerXml;
//rw.Attributes.Append(attribute);
mes.Attributes.Append(attribute);
}
}
}
Any help would be appreciated.
Update: This is what I am getting.
<data>
<row InventoryItemId="11201" ItemDescription="BREAD LG BUN 5" CategoryName="BAKERY" />
<inventoryitem>
<measures>
<measure Measure="TR"></measure>
<measure Measure="EACH"></measure>
</measures>
<locations />
<skus />
</inventoryitem>
</data>
I figured it out. By wrapping each node inside a row node loop I get the results I was looking for.
var item = idnode.InnerXml;
XmlNodeList rwList = doc.SelectNodes(String.Format("data/row[#InventoryItemId='{0}']",item));
var rwCount = rwList.Count;
foreach (XmlNode rw in rwList)
{
XmlNodeList msList = id.SelectNodes("measures/measure");
foreach (XmlNode mes in msList)
{
XmlNode msnode = mes.SelectSingleNode("name");
{
var attribute = doc.CreateAttribute("Measure");
attribute.Value = msnode.InnerXml;
if (rwCount > 0)
{
rw.Attributes.Append(attribute);
rwCount--;
}
else
{
XmlNode clonenode = rw.Clone();
clonenode.Attributes.Append(attribute);
nd.AppendChild(clonenode);
}
}
}
}
My xml file:
<?xml version="1.0" encoding="utf-8"?>
<layout name="layout">
<section name="Header">
<placeholder name="headers" width="30" class="header">sam,pam</placeholder>
</section>
<section name="Content">
<placeholder name="RightA" width="55">location</placeholder>
</section>
</layout>
I want to replace whole node if its contain sam.Means if node contains sam I want to rewrite node:
<placeholder name="headers" width="4,5,91">sam,sam2,pam</placeholder>
instead of:
<placeholder name="headers" width="30" class="header">sam,pam</placeholder>
In c#:
XmlDocument doc = new XmlDocument();
string sFileName = #"FileNameWithPath";
doc.Load(sFileName );
foreach (XmlNode ....... )
{
//Need help hear how to loop and replace.
}
Thanks.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("Path");
XmlNodeList nodeList = xmlDoc.SelectNodes("section") ;
foreach (XmlNode node in nodeList)
{
XmlNode childNode = node.SelectSingleNode("placeholder");
if (childNode.Value.Contains("sam"))
{
childNode.Value = "sam,pam,sam2";
childNode.Attributes["width"].Value = "4,5,91";
}
}
xmlDoc.Save("Path");
Try using an XDocument for better control over find and replace.
XDocument myDocument = XDocument.Load("path to my file");
foreach (XElement node in myDocument.Root.Descendants("placeholder"))
{
if (node.Value.Contains("same"))
{
XElement newNode = new XElement("placeholder");
newNode.Add(new XAttribute("header", node.Attribute("header").Value); // if you want to copy the current value
newNode.Add(new XAttribute("width", "some new value"));
node.ReplaceWith(newNode);
}
}
Is there a way to get the innertext of a node when the node is inside a collection
Currently i have this
Collection<string> DependentNodes = new Collection<string>();
foreach (XmlNode node in nodes)
{
for (int i = 0; i < node.ChildNodes.Count; i++)
{
DependentNodes.Add(node.ChildNodes[i].InnerXml);
//the reason i'm using InnerXml is that it will return all the child node of testfixture in one single line,then we can find the category & check if there's dependson
}
}
string selectedtestcase = "abc_somewords";
foreach (string s in DependentNodes)
{
if(s.Contains(selectedtestcase))
{
MessageBox.Show("aaa");
}
}
When i debug string s or the index has this inside of it[in a single line]
<testfixture name="1" description="a">
<categories>
<category>abc_somewords</category>
</categories>
<test name="a" description="a">
<dependencies>
<dependson typename="dependsonthis" />
</dependencies>
</test>
</testfixture>
What i'm trying to do is when we reach "testfixture 1" it will find "abc_somewords" & search the "dependson typename"node(if any) and get the "typename"(which is "dependonthis").
Could you use linq to xml. Something like the below might be a decent start
xml.Elements("categories").Where(x => x.Element("category").Value.Contains(selectedtestcase));
This is off the top of my head so might will need refining
P.S. Use XElement.Load or XElement.Parse to get your xml into XElements
Since you already working with XmlNode you could use a XPath expression to select the desired textfixture node, and select the dependency value:
XmlDocument doc = // ...
XmlNode node = doc.SelectSingleNode("//testfixture[contains(categories/category, \"abc\")]/test/dependencies/dependson/");
if (node != null)
{
MessageBox.Show(node.Attributes["typename"]);
}
This selects the dependson node which belongs to a testfixture node with a category containing "abc". node.Attributes["typename"] will return the value of the typename attribute.
Edited:
Updated XPath expression to the more specific question information
Assumptions
As you are looping in your code and wanting to create a collection I'm assuming the actual Xml File has several testfixture nodes inside such as the below assumed example:
<root>
<testfixture name="1" description="a">
<categories>
<category>abc_somewords</category>
</categories>
<test name="a" description="a">
<dependencies>
<dependson typename="dependsonthis" />
</dependencies>
</test>
</testfixture>
<testfixture name="2" description="a">
<categories>
<category>another_value</category>
</categories>
<test name="b" description="a">
<dependencies>
<dependson typename="secondentry" />
</dependencies>
</test>
</testfixture>
<testfixture name="3" description="a">
<categories>
<category>abc_somewords</category>
</categories>
<test name="c" description="a">
<dependencies>
<dependson typename="thirdentry" />
</dependencies>
</test>
</testfixture>
</root>
The Code using Linq to Xml
To use Linq you must reference the following name spaces:
using System.Linq;
using System.Xml.Linq;
Using Linq To Xml on the above assumed xml file structure would look like this:
// To Load Xml Content from File.
XDocument doc1 = XDocument.Load(#"C:\MyXml.xml");
Collection<string> DependentNodes = new Collection<string>();
var results =
doc1.Root.Elements("testfixture")
.Where(x => x.Element("categories").Element("category").Value.Contains("abc_somewords"))
.Elements("test").Elements("dependencies").Elements("dependson").Attributes("typename").ToArray();
foreach (XAttribute attribute in results)
{
DependentNodes.Add(attribute.Value.Trim());
}
Result
The resulting Collection will contain the following:
As you can see, only the text of the typename attribute has been extracted where the dependson nodes where in a testfixture node which contained a category node with the value of abc_somewords.
Additional Notes
If you read the xml from a string you can also use this:
// To Load Xml Content from a string.
XDocument doc = XDocument.Parse(myXml);
If your complete Xml structure is different, feel free to post it and I change the code to match.
Have Fun.
I don't know what is "nodes" you are using.
Here is code with your requirement(What I understood).
Collection<XmlNode> DependentNodes = new Collection<XmlNode>();
XmlDocument xDoc = new XmlDocument();
xDoc.Load(#"Path_Of_Your_xml");
foreach (XmlNode node in xDoc.SelectNodes("testfixture")) // Here I am accessing only root node. Give Xpath if ur requrement is changed
{
for (int i = 0; i < node.ChildNodes.Count; i++)
{
DependentNodes.Add(node.ChildNodes[i]);
}
}
string selectedtestcase = "abc_somewords";
foreach (var s in DependentNodes)
{
if (s.InnerText.Contains(selectedtestcase))
{
Console.Write("aaa");
}
}
using System;
using System.Xml;
namespace ConsoleApplication6
{
class Program
{
private const string XML = "<testfixture name=\"1\" description=\"a\">" +
"<categories>" +
"<category>abc_somewords</category>" +
"</categories>" +
"<test name=\"a\" description=\"a\">" +
"<dependencies>" +
"<dependson typename=\"dependsonthis\" />" +
"</dependencies>" +
"</test>" +
"</testfixture>";
static void Main(string[] args)
{
var document = new XmlDocument();
document.LoadXml(XML);
var testfixture = document.SelectSingleNode("//testfixture[#name = 1]");
var category = testfixture.SelectSingleNode(".//category[contains(text(), 'abc_somewords')]");
if(category != null)
{
var depends = testfixture.SelectSingleNode("//dependson");
Console.Out.WriteLine(depends.Attributes["typename"].Value);
}
Console.ReadKey();
}
}
}
Output: dependsonthis
I have a xml-file:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<root>
<level>
<node1 />
<node2 />
<node3 />
</level>
</root>
What is the simplest way to insert values in node1, node2, node3 ?
C#, Visual Studio 2005
Here you go:
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(#"
<root>
<level>
<node1 />
<node2 />
<node3 />
</level>
</root>");
XmlElement node1 = xmldoc.SelectSingleNode("/root/level/node1") as XmlElement;
if (node1 != null)
{
node1.InnerText = "something"; // if you want a text
node1.SetAttribute("attr", "value"); // if you want an attribute
node1.AppendChild(xmldoc.CreateElement("subnode1")); // if you want a subnode
}
//Here is the variable with which you assign a new value to the attribute
string newValue = string.Empty
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlFile);
XmlNode node = xmlDoc.SelectSingleNode("Root/Node/Element");
node.Attributes[0].Value = newValue;
xmlDoc.Save(xmlFile);
Credit goes to Padrino.
How to change XML Attribute
XElement t = XElement.Load("filePath");
t.Element("level").Element("node1").Value = "";
t.Element("level").Element("node2").Value = "";
t.Element("level").Element("node3").Value = "";
t.Save("filePath");
Use AppendChild method to inser a child inside a node.
yournode.AppendChild(ChildNode);
link text