Let's say we have the following xml :
<?xml version="1.0" encoding="UTF-16"?>
<OrderExchangeMessage version="9.0" type="AddOrder"
xmlns:xs="xxx"
xmlns:xsi="xxx"
xmlns="xxx">
<Command>
<AddOrderRequest>
<Order>
<OrderID>xxx</OrderID>
<InnerOrder>
<RestorationOrder version="5.0">
<ModelElements>
<ModelElement displayName="red car">
<files>
<file path="pathtofile"/>
</files>
</ModelElement>
<ModelElement displayName="red truck">
<files>
<file path="pathtofile"/>
</files>
</ModelElement>
<ModelElement displayName="green car">
<files>
<file path="pathtofile"/>
</files>
</ModelElement>
</ModelElements>
</RestorationOrder>
</InnerOrder>
</Order>
</AddOrderRequest>
</Command>
</OrderExchangeMessage>
How can I retrieve the value of file path only if the attribute of ModelElement contains "red" ?
So I need to know which file goes for a red car and which file for a red truck.
I also tried to get a parent in order to look for child, but got no luck so far.
XmlNodeList? nodeListItems = xmldoc.SelectNodes("/OrderExchangeMessage[#version='9.0']/" +
"Command/AddOrderRequest/Order/InnerOrder/" +
"RestorationOrder[#version='5.0']/" +
"ModelElements");
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
XmlNodeList modelElements = doc.GetElementsByTagName("ModelElement");
foreach (XmlNode modelElement in modelElements)
{
XmlNode displayName = modelElement.Attributes.GetNamedItem("displayName");
if (displayName != null && displayName.Value.Contains("red"))
{
XmlNode path = modelElement["files"]["file"].Attributes.GetNamedItem("path");
Console.WriteLine(path.Value);
}
}
This should do the trick.
xml is the xml document
This code iterates all ModelElement and Checks displayName for the value of red
If you want to use your SelectNodes code, you'll have to have a NameSpaceManager, and the xpath has to have "xxx:" before each node path.
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmldoc.NameTable);
nsmgr.AddNamespace("xxx", xmldoc.DocumentElement.NamespaceURI);
XmlNodeList? nodeListItems = xmldoc.SelectNodes("/xxx:OrderExchangeMessage[#version='9.0']/xxx:" +
"Command/xxx:AddOrderRequest/xxx:Order/xxx:InnerOrder/xxx:" +
"RestorationOrder[#version='5.0']/xxx:" +
"ModelElements", nsmgr);
Please try the following solution.
It is using LINQ to XML API of the .Net Framework. It is available since 2007.
The input XML has a default namespace. It should be taken care of.
c#
void Main()
{
const string filePath = #"e:\Temp\LockedInside.xml";
XDocument xdoc = XDocument.Load(filePath);
XNamespace ns = xdoc.Root.GetDefaultNamespace();
var ModelElements = xdoc.Descendants(ns + "ModelElement")?
.Where(d => d.Attributes("displayName").FirstOrDefault().Value.StartsWith("red"));
foreach (var ModelElement in ModelElements)
{
Console.WriteLine("displayName='{0}', file_path='{1}'"
, ModelElement.Attribute("displayName").Value
, ModelElement.Element(ns + "files").Element(ns + "file").Attribute("path").Value);
}
}
Output
displayName='red car', file_path='pathtofile'
displayName='red truck', file_path='pathtofile'
Related
I am trying to get some data from an XML document. I have no control over the schema. If it were up to me I would have chosen another schema. I am using C#'s XPATH library to get the data.
XML DOC
<Journals>
<name>Title of Journal</name>
<totalvolume>2</totalvolume>
<JournalList>
<Volume no="1">
<Journal>
<issue>01</issue>
<Title>Title 1</Title>
<date>1997-03-10</date>
<link>www.somelink.com</link>
</Journal>
<Journal>
<issue>02</issue>
<Title>Title 3</Title>
<date>1997-03-17</date>
<link>www.somelink.com</link>
</Journal>
</Volume>
<Volume no="2">
<Journal>
<issue>01</issue>
<Title>Title 1</Title>
<date>1999-01-01</date>
<link>www.somelink.com</link>
</Journal>
<Journal>
<issue>01</issue>
<Title>Title 2</Title>
<date>1999-01-08</date>
<link>www.somelink.com</link>
</Journal>
</Volume>
</JournalList>
</Journals>
I am trying to get all the data in the Volume 2 node. Here is what I tried so far:
C# Code:
protected void loadXML(string url)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(url);
string strQuery = "Volume[#no='2']";
XmlElement nodeList = xmlDoc.DocumentElement;
XmlNodeList JournalList = nodeList.SelectNodes(strQuery);
foreach (XmlElement Journal in JournalList)
{
XmlElement temp = Journal;
}
}
It seems there are no nodes in JournalList. Anyone? Thanks in advance/
Your code is looking for "Volume" nodes directly under the "Journals" node
Change this:
string strQuery = "Volume[#no='2']";
To this, in order to look for "Volume" nodes under the "JournalList" node:
string strQuery = "JournalList/Volume[#no='2']";
Also, there's a couple typos in your XML:
</Volume no="2"> -> <Volume no="2"> // no open tag found
</Journal> -> </Journals> // expecting end tag </Journals>
From your comment below:
how would I go about access each journal? for example. I want irrate through each "journal" and get the title of the journal?
In order to do that, you could modify your code slightly:
var nodeList = xmlDoc.DocumentElement;
var volume = nodeList.SelectSingleNode(strQuery);
foreach (XmlElement journal in volume.SelectNodes("Journal"))
{
var title = journal.GetElementsByTagName("Title")[0].InnerText;
}
Also you can use Linq to XML:
using System.Xml.Linq;
//...
string path="Path of your xml file"
XDocument doc = XDocument.Load(path);
var volume2= doc.Descendants("Volume").FirstOrDefault(e => e.Attribute("no").Value == "2");
Hi i am trying to get value from xml but it shows node null.
Here is my xml file.
<?xml version="1.0" encoding="utf-8"?>
<result xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.cfhdocmail.com/TestAPI2/Result.xsd https://www.cfhdocmail.com/TestAPI2/Result.xsd" xmlns="https://www.cfhdocmail.com/TestAPI2/Result.xsd">
<data>
<key>MailingGUID</key>
<value>0aa2b2e3-7afa-4002-ab2f-9eb4cbe33ae7</value>
</data>
<data>
<key>OrderRef</key>
<value>52186</value>
</data>
</result>
I want to get "MailingGUID" value.
Here is the code that i have tried:
private void readXML()
{
XmlDocument xml = new XmlDocument();
// You'll need to put the correct path to your xml file here
xml.Load(Server.MapPath("~/XmlFile11.xml"));
// Select a specific node
XmlNode node = xml.SelectSingleNode("result/data/value");
// Get its value
string name = node.InnerText;
}
Please tell me how i can get MailingGUID value.
Thanks
UPDATE:
I think there might be something wrong with your schemas, I removed references to them and your code worked fine. I tried this:
const string str = "<?xml version=\"1.0\" encoding=\"utf-8\"?><result><data><key>MailingGUID</key><value>0aa2b2e3-7afa-4002-ab2f-9eb4cbe33ae7</value></data><data><key>OrderRef</key><value>52186</value></data></result>";
var xml = new XmlDocument();
xml.LoadXml(str);
xml.DocumentElement.SelectSingleNode("/result/data/value").InnerText
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
//Parsing of xml is done here
Document doc = builder.parse(new File("C:\\Users\\User_Name\\Documents\\My Received Files\\PDSL_ABM.xml"));
//Here we get the root element of XML and print out
doc.getDocumentElement().normalize();
System.out.println ("Root element of the doc is " + doc.getDocumentElement().getNodeName());
NodeList list = doc.getElementsByTagName("MailingGUID");
int totalMailingGUID =list.getLength();
System.out.println("Total no of MailingGUID : " + totalSupplierPartID);
//Traversing all the elements from the list and printing out its data
for (int i = 0; i < list.getLength(); i++) {
//Getting one node from the list.
Node childNode = list.item(i);
System.out.println("MailingGUID : " + childNode.getTextContent());
}
I try to parse this XML file (config file from Chirpy):
<?xml version="1.0" encoding="utf-8" ?>
<root xmlns="urn:ChirpyConfig"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:ChirpyConfig http://www.weirdlover.com/chirpy/chirp.xsd">
<FileGroup Name="Built.debug.js" Minify="false">
<File Path="jquery/jquery-1.7.2.js"/>
<File Path="jquery.address/jquery.address-1.4.js" />
</FileGroup>
</root>
with this code:
var path = Server.MapPath("~/Scripts/ScriptfilesMashup.chirp.config");
var file = new XPathDocument(path);
var nav = file.CreateNavigator();
var nodes = nav.Select("/root/FileGroup/File");
but nodes is always empty, regardless of how I call the nav.Select method. I barely used XPath before so maybe I'm doing it wrong - but what? Only the selector * gives me the root node.
What would be the selector to get the Path Attribute of all File nodes?
EDIT: SOLUTION
Thanks to Kirill, the final solution looks like this:
var path = Server.MapPath("~/Scripts/ScriptfilesMashup.chirp.config");
var file = new XPathDocument(path);
var nav = file.CreateNavigator();
var ns = "urn:ChirpyConfig";
XmlNamespaceManager nsMgr = new XmlNamespaceManager(nav.NameTable);
nsMgr.AddNamespace("x", ns);
var nodes = nav.Select("/x:root/x:FileGroup/x:File/#Path", nsMgr);
while(nodes.MoveNext())
{
var path = nodes.Current.Value;
}
It is because elements root, FileGroup and File are defined in urn:ChirpyConfig namespace.
Use this:
XPathDocument xmldoc = new XPathDocument(xmlFile);
XPathNavigator nav = xmldoc.CreateNavigator();
XmlNamespaceManager nsMgr = new XmlNamespaceManager(nav.NameTable);
nsMgr.AddNamespace("x", "urn:ChirpyConfig");
XPathNavigator result = nav.SelectSingleNode("/x:root/x:FileGroup/x:File", nsMgr);
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
My Method:
if (File.Exists( #"C:\config.xml"))
{
System.Xml.XmlDocument xd = new System.Xml.XmlDocument();
xd.Load( #"C:\config.xml");
System.Xml.XmlElement root = xd.DocumentElement;
System.Xml.XmlNodeList nl = root.SelectNodes("/config");
foreach (System.Xml.XmlNode xnode in nl)
{
string name = xnode.Name;
string value = xnode.InnerText;
string nv = name + "|" + value;
Send(nv);
}
My Xml Doc
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<config>
<bla>D</bla>
<def>300</def>
<ttOUT>34000</ttOUT>
<num>3800</num>
<pw>help</pw>
<err>1</err>
....and so on
</config>
Now my method returns the first 2 and nothing else.
What am i doing wrong...
use the System.Xml namespace to avoid long type qualifications ie...
using System.Xml;
Then try something like this..
XmlNodeList nl = xd.SelectNodes("config");
XmlNode root = nl[0];
foreach (XmlNode xnode in root.ChildNodes)
{
string name = xnode.Name;
string value = xnode.InnerText;
string nv = name + "|" + value;
Send(nv);
}
I believe there is something wrong with your method.
a) I don't think SelectNodes should take the /config argument, rather it should take config.
b) After selecting the first (and only - XML files in .Net must have one and only one root node) root node you need to iterate through the ChildNodes of the root.
root is the <config> tag, so I don't understand how root.SelectNodes("/config") should work at all. Use root.Childnodes instead.