I have this chunk of XML
<EnvelopeStatus>
<CustomFields>
<CustomField>
<Name>Matter ID</Name>
<Show>True</Show>
<Required>True</Required>
<Value>3</Value>
</CustomField>
<CustomField>
<Name>AccountId</Name>
<Show>false</Show>
<Required>false</Required>
<Value>10804813</Value>
<CustomFieldType>Text</CustomFieldType>
</CustomField>
I have this code below:
// TODO find these programmatically rather than a strict path.
var accountId = envelopeStatus.SelectSingleNode("./a:CustomFields", mgr).ChildNodes[1].ChildNodes[3].InnerText;
var matterId = envelopeStatus.SelectSingleNode("./a:CustomFields", mgr).ChildNodes[0].ChildNodes[3].InnerText;
The problem is, sometimes the CustomField with 'Matter ID' might not be there. So I need a way to find the element based on what 'Name is', i.e. a programmatic way of finding it. I can't rely on indexes being accurate.
You can use this code to read innertext from a specific element:
XmlDocument doc = new XmlDocument();
doc.Load("your.xml");
XmlNodeList Nodes= doc.SelectNodes("/EnvelopeStatus/CustomField");
if (((Nodes!= null) && (Nodes.Count > 0)))
{
foreach (XmlNode Level1 in Nodes)
{
if (Level1.ChildNodes[1].Name == "name")
{
string text = Convert.ToInt32(Level1.ChildNodes[1].InnerText.ToString());
}
}
}
You can often find anything in a XML document by utilizing the XPath capabilities that is available directly in the .NET Framework versions.
Maybe create a small XPath parser helper class
public class EnvelopeStatusParser
{
public XmlNodeList GetNodesWithName(XmlDocument doc, string name)
{
return doc.SelectNodes($"//CustomField[Name[text()='{name}']]");
}
}
and then call it like below to get all CustomFields which have a Name that equals what you need to search for
// Creating the XML Document in some form - here reading from file
XmlDocument doc = new XmlDocument();
doc.Load(#"envelopestatus.xml");
var parser = new EnvelopeStatusParser();
var matchingNodes = parser.GetNodesWithName(doc, "Matter ID");
Console.WriteLine(matchingNodes);
matchingNodes = parser.GetNodesWithName(doc, "NotHere");
Console.WriteLine(matchingNodes);
There exist numerous XPath cheat sheets around - like this one from LaCoupa - xpath-cheatsheet which can be quiet helpful to fully utilize XPath on XML structures.
Related
This question already has answers here:
How does one parse XML files? [closed]
(12 answers)
Closed 7 years ago.
I'm starting working with XML files and I know little about it.
What I need is read the value from a certain tag of a XML file
<Tag>
<Name>PBAS</Name>
<ID>1</ID>
<Description>Array of sequence characters as edited by user</Description>
<Type>char</Type>
<Elements>163</Elements>
<Size>163</Size>
<Value>TCCGAACAAGCGGCGAGTGCTGGGCGAGTGGCCGCGGGGCTGTGGTCCTGTGCACGGTGATCGCAAGGGCCCCCGGGGCTTGCTGGTCTTCCCTAACGGTTCGTGGAACCCCCGAAGCTGGGGGCTGGCCAGGGGCTTAAGGAACCCTTCCTAAATTAACTAC</Value>
</Tag>
I need, in the example above, getting the string between the "Value"(the string TCCGA...) of the tag named "PBAS" with "ID 1".
But I need this value just from the tag named PBAS with "ID1", since the XML document has other "values" from other tags named differently.
Thanks a lot!
var yourval = XDocument.Load(filename)
.XPathSelectElement("//Tag[Name='PBAS' and ID='1']")
.Element("Value")
.Value;
or
var yourval = (string)XDocument.Load(filename)
.XPathSelectElement("//Tag[Name='PBAS' and ID='1']/Value");
or (using only Linq)
var yourval = XDocument.Load(filename)
.Descendants("Tag")
.Where(t => (string)t.Element("Name") == "PBAS")
.Where(t => (string)t.Element("ID") == "1")
.First()
.Element("Value")
.Value;
PS: Necessary namespaces: System.Xml, System.Xml.XPath, and System.Xml.Linq . Also Read about Linq2Xml and Xpath
The technology to select nodes from XML is called XPath. Basically you create a path of element names separated by / like
/Tag/Value
To specify conditions, put them in square brackets at the place from where you want to start the condition:
/Tag[./Name/text()="PBAS"][./ID/text()="1"]/Value
Above XPath is good for demonstration purposes, since it explains how it works. In practice, this would be simplified to
/Tag[Name="PBAS"][ID="1"]/Value
Code:
using System.Xml;
var doc = new XmlDocument();
doc.LoadXml(xml);
var nodes = doc.SelectNodes("/Tag[./Name/text()=\"PBAS\"][./ID/text()=\"1\"]/Value");
foreach (XmlElement node in nodes)
{
Console.WriteLine(node.InnerText);
}
Console.ReadLine();
You can use the below code:
string xmlFile = File.ReadAllText(#"D:\Work_Time_Calculator\10-07-2013.xml");
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(xmlFile);
XmlNodeList xnList = xmldoc.SelectNodes("/Tag");
string Value ="";
foreach (XmlNode xn in xnList)
{
string ID = xn["ID"].InnerText;
if(ID =="1")
{
value = xn["Value"].InnerText;
}
}
I have been trying to extract one value from a XML file, and then store it on the same file but in another node, I tried all the examples i've found on the net, read XPath Syntax documentation like hell and still can't get it to work.
I must take the <Documento ID="F60T33"> ID Value (which may vary) and copy it into <Reference URI="#F60T33">.
But I can't even do that if I can't manage to parse the lines, most of times node/variables/"", or I get an "object reference not established as object instance error".
Here's the code:
// Create a new XML document.
XmlDocument xmlDoc = new XmlDocument();
// Load an XML file into the XmlDocument object.
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load(pfile);
//TEST !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! PROBLEMA
XmlNodeList Documentos = xmlDoc.GetElementsByTagName("//Documento");
XmlNodeList DatosDocumento = ((XmlElement)Documentos[0]).GetElementsByTagName("ID");
foreach (XmlElement nodo in DatosDocumento)
{
int I = 0;
XmlNodeList ID = nodo.GetElementsByTagName("ID");
Console.WriteLine("Elemento nombre ... {0}}", ID[i].InnerText);
}
//
XmlNodeList nodes = xmlDoc.SelectNodes("EnvioDTE");
XmlNode nodesimple = xmlDoc.SelectSingleNode("EnvioDTE");
Console.WriteLine("Lista Nodos: " + nodes.Count);
Console.WriteLine("Nodo Simple: " + nodesimple.InnerText);
foreach (XmlNode node in nodes)
{
string id = node.Attributes["ID"].InnerText;
Console.WriteLine(id);
}
I am almost certain the problem is on the XPath Syntax, but I can't get it to work.
Sadly I can't use XDocument as im using .NET 3.5 for this task, I would really appreciate some help on this, by behand apologize my bad english
As the XML file is too big, I'll put it here on this URL
http://puu.sh/bVNDc/31e4da5a26.xml
If you can get your references right for using System.Linq.XDocument you can do:
string idValue = xDocument.XPathSelectElement("//EnvioDTE/SetDTE")
.Attributes().SingleOrDefault(a => a.Name == "ID").Value;
I'm making a small tool for checking the material number from the XML file.
I know this quite easy for you experts and I would like to ask for your help on this to get me started on this. On my machine I have .NET 2.0 framework I guess, and VS C# Express 2005 installed.
I have an XML that contains data of a material. It is located at my local drive. I am able now to browse the XML file and save the file in a string variable. Well, that's what I have done so far..
if(folderBrowserDialog1.ShowDialog() == DialogResult.OK)
{
string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath, "Product.xml");
string prodFile = files[0];
...
...
Suppose this is the structure of the XML:
<Record>
<Product>
<Material_Number>20209485</Material_Number>
<Product_Type>Type1</Product_Type>
...
...
</Product>
</Record>
How can I get the material number value?
You can use the XmlDocument class for loading your XML File into a DOM.
MSDN - This class implements the W3C Document Object Model (DOM) Level 1 Core and the Core DOM Level 2. The DOM is an in-memory (cache) tree representation of an XML document and enables the navigation and editing of this document. Because XmlDocument implements the IXPathNavigable interface it can also be used as the source document for the XslTransform class.
Sample
There are many ways to read your value. I really encourage you to read Working with Xml DOM
XmlNodeList list = xml.GetElementsByTagName("Product");
XmlAttributeCollection attr = list[0].Attributes;
string materialNumber = list[0].ChildNodes[0].InnerText;
or
XmlNodeList list = xml.GetElementsByTagName("Material_Number");
string materialNumber = list[0].InnerText;
More Information
MSDN - XmlDocument Class
Working with Xml DOM
You could also use XPathNavigator and XPathExpression with XmlDocument.
var xmlDoc = new XmlDocument();
xmlDoc.Load("Product.xml") //or xmlDoc.LoadXml(xmlString);
var xmlNav = xmlDoc.CreateNavigator();
string materialNum;
var iterator = xmlNav.Select("/Record/Product/Material_Number");
if (iterator.MoveNext() && iterator.Current != null)
materialNum = iterator.Current.Value;
If you use .Net 3.0+ you could use System.Xml.Linq.XDocument.
var xdoc = XDocument.Load("Product.xml"); //or var xdoc = XDocument.Parse(xmlString);
var materialNum = xdoc.Root.Element("Product").Element("Material_Number").Value;
I was able to find a solution. Not so elegant though...
XmlDocument xmlDoc= new XmlDocument();
xmlDoc.Load(#"C:\Product.xml");
XmlNodeList a = xmlDoc.GetElementsByTagName("Material_Number");
string materialNumber = a[0].InnerText;
I have several XML files that I wish to read attributes from. My main objective is to apply syntax highlighting to rich text box.
For example in one of my XML docs I have: <Keyword name="using">[..] All the files have the same element: Keyword.
So, how can I get the value for the attribute name and put them in a collection of strings for each XML file.
I am using Visual C# 2008.
The other answers will do the job - but the syntax highlighting thingy and the several xml files you say you have makes me thinks you need something faster, why not use a lean and mean XmlReader?
private string[] getNames(string fileName)
{
XmlReader xmlReader = XmlReader.Create(fileName);
List<string> names = new List<string>();
while (xmlReader.Read())
{
//keep reading until we see your element
if (xmlReader.Name.Equals("Keyword") && (xmlReader.NodeType == XmlNodeType.Element))
{
// get attribute from the Xml element here
string name = xmlReader.GetAttribute("name");
// --> now **add to collection** - or whatever
names.Add(name);
}
}
return names.ToArray();
}
Another good option would be the XPathNavigator class - which is faster than XmlDoc and you can use XPath.
Also I would suggest to go with this approach only IFF after you try with the straightforward options you're not happy with performance.
You could use XPath to get all the elements, then a LINQ query to get the values on all the name atttributes you find:
XDocument doc = yourDocument;
var nodes = from element in doc.XPathSelectElements("//Keyword")
let att = element.Attribute("name")
where att != null
select att.Value;
string[] names = nodes.ToArray();
The //Keyword XPath expression means, "all elements in the document, named "Keyword".
Edit: Just saw that you only want elements named Keyword. Updated the code sample.
Like others, I would suggest using LINQ to XML - but I don't think there's much need to use XPath here. Here's a simple method to return all the keyword names within a file:
static IEnumerable<string> GetKeywordNames(string file)
{
return XDocument.Load(file)
.Descendants("Keyword")
.Attributes("name")
.Select(attr => attr.Value);
}
Nice and declarative :)
Note that if you're going to want to use the result more than once, you should call ToList() or ToArray() on it, otherwise it'll reload the file each time. Of course you could change the method to return List<string> or string[] by -adding the relevant call to the end of the chain of method calls, e.g.
static List<string> GetKeywordNames(string file)
{
return XDocument.Load(file)
.Descendants("Keyword")
.Attributes("name")
.Select(attr => attr.Value)
.ToList();
}
Also note that this just gives you the names - I would have expected you to want the other details of the elements, in which case you'd probably want something slightly different. If it turns out you need more, please let us know.
You could use LINQ to XML.
Example:
var xmlFile = XDocument.Load(someFile);
var query = from item in xmlFile.Descendants("childobject")
where !String.IsNullOrEmpty(item.Attribute("using")
select new
{
AttributeValue = item.Attribute("using").Value
};
You'll likely want to use XPath. //Keyword/#name should get you all of the keyword names.
Here's a good introduction: .Net and XML XPath Queries
**<Countries>
<Country name ="ANDORRA">
<state>Andorra (general)</state>
<state>Andorra</state>
</Country>
<Country name ="United Arab Emirates">
<state>Abu Z¸aby</state>
<state>Umm al Qaywayn</state>
</Country>**
public void datass(string file)
{
string file = HttpContext.Current.Server.MapPath("~/App_Data/CS.xml");
XmlDocument doc = new XmlDocument();
if (System.IO.File.Exists(file))
{
//Load the XML File
doc.Load(file);
}
//Get the root element
XmlElement root = doc.DocumentElement;
XmlNodeList subroot = root.SelectNodes("Country");
for (int i = 0; i < subroot.Count; i++)
{
XmlNode elem = subroot.Item(i);
string attrVal = elem.Attributes["name"].Value;
Response.Write(attrVal);
XmlNodeList sub = elem.SelectNodes("state");
for (int j = 0; j < sub.Count; j++)
{
XmlNode elem1 = sub.Item(j);
Response.Write(elem1.InnerText);
}
}
}
I'd like to get all the element name from a xml file, for example the xml file is,
<BookStore>
<BookStoreInfo>
<Address />
<Tel />
<Fax />
<BookStoreInfo>
<Book>
<BookName />
<ISBN />
<PublishDate />
</Book>
<Book>
....
</Book>
</BookStore>
I would like to get the element's name of "BookName". "ISBN" and "PublishDate " and only those names, not include " BookStoreInfo" and its child node's name
I tried several ways, but doesn't work, how can I do it?
Well, with XDocument and LINQ-to-XML:
foreach(var name in doc.Root.DescendantNodes().OfType<XElement>()
.Select(x => x.Name).Distinct())
{
Console.WriteLine(name);
}
There are lots of similar routes, though.
Using XPath
XmlDocument xdoc = new XmlDocument();
xdoc.Load(something);
XmlNodeList list = xdoc.SelectNodes("//BookStore");
gives you a list with all nodes in the document named BookStore
I agree with Adam, the ideal condition is to have a schema that defines the content of xml document. However, sometimes this is not possible. Here is a simple method for iterating all of the nodes of an xml document and using a dictionary to store the unique local names. I like to keep track of the depth of each local name, so I use a list of int to store the depth. Note that the XmlReader is "easy on the memory" since it does not load the entire document as the XmlDocument does. In some instances it makes little difference because the size of the xml data is small. In the following example, an 18.5MB file is read with an XmlReader. Using an XmlDocument to load this data would have been less effecient than using an XmlReader to read and sample its contents.
string documentPath = #"C:\Docs\cim_schema_2.18.1-Final-XMLAll\all_classes.xml";
Dictionary<string, List<int>> nodeTable = new Dictionary<string, List<int>>();
using (XmlReader reader = XmlReader.Create(documentPath))
{
while (!reader.EOF)
{
if (reader.NodeType == XmlNodeType.Element)
{
if (!nodeTable.ContainsKey(reader.LocalName))
{
nodeTable.Add(reader.LocalName, new List<int>(new int[] { reader.Depth }));
}
else if (!nodeTable[reader.LocalName].Contains(reader.Depth))
{
nodeTable[reader.LocalName].Add(reader.Depth);
}
}
reader.Read();
}
}
Console.WriteLine("The node table has {0} items.",nodeTable.Count);
foreach (KeyValuePair<string, List<int>> kv in nodeTable)
{
Console.WriteLine("{0} [{1}]",kv.Key, kv.Value.Count);
for (int i = 0; i < kv.Value.Count; i++)
{
if (i < kv.Value.Count-1)
{
Console.Write("{0}, ", kv.Value[i]);
}
else
{
Console.WriteLine(kv.Value[i]);
}
}
}
The purists way of doing this (and, to be fair, the right way) would be to have a schema contract definition and read it in that way. That being said, you could do something like this...
List<string> nodeNames = new List<string>();
foreach(System.Xml.XmlNode node in doc.SelectNodes("BookStore/Book"))
{
foreach(System.Xml.XmlNode child in node.Children)
{
if(!nodeNames.Contains(child.Name)) nodeNames.Add(child.Name);
}
}
This is, admittedly, a rudimentary method for obtaining the list of distinct node names for the Book node's children, but you didn't specify much else in the way of your environment (if you have 3.5, you could use LINQ to XML to make this a little prettier, for example), but this should get the job done regardless of your environment.
If you're using C# 3.0, you can do the following:
var data = XElement.Load("c:/test.xml"); // change this to reflect location of your xml file
var allElementNames =
(from e in in data.Descendants()
select e.Name).Distinct();
You can try doing it using XPATH.
XmlDocument doc = new XmlDocument();
doc.LoadXml("xml string");
XmlNodeList list = doc.SelectNodes("//BookStore/Book");
If BookStore is ur root element then u can try following code
XmlDocument doc = new XmlDocument();
doc.Load(configPath);
XmlNodeList list = doc.DocumentElement.GetElementsByTagName("Book");
if (list.Count != 0)
{
for (int i = 0; i < list[0].ChildNodes.Count; i++)
{
XmlNode child = list[0].ChildNodes[i];
}
}