how can I access data coming from an XML File into variables?
<RESULTS>
<ROW>
<COLUMN NAME="OM_USER"><![CDATA[TEXT]]></COLUMN>
<COLUMN NAME="LASTNAME"><![CDATA[TEXT]]></COLUMN>
<COLUMN NAME="FIRSTNAME"><![CDATA[TEXT]]></COLUMN>
<COLUMN NAME="PHONE"><![CDATA[TEXT]]></COLUMN>
</ROW>
</RESULTS>
this is what i tried but the output is weired
XDocument xmlDocument = XDocument.Load(#"PATH");
var xElement = xmlDocument.Element();
if (xElement != null)
{
foreach (var child in xElement.Elements())
{
Console.WriteLine(child.Name + ": " + child.Value);
}
}
My Output come like this:
ROW: TEXTEXTTEXTTEXT
ROW: TEXTEXTTEXTTEXT
ROW: TEXTEXTTEXTTEXT
ROW: TEXTEXTTEXTTEXT
Thanks for any help =)
The problem that you are facing is that you are a level too high in the xml tree. By stating
var xElement = xmlDocument.Elements();
You get all the elements from the top of the xdocument, which is the root named "RESULTS"
Your foreach is looping over all the child's of the "RESULTS" element which is only "ROW". If you the specify that you want to print the name of the child (ROW) and its value you get all the text that element "ROW" and all it's children have. If you use the debugger you will see this content.
By changing your code to something simular below you will get the correct outcome
const string msg = "<RESULTS><ROW><COLUMN NAME=\"OM_USER\"><![CDATA[TEXT]]></COLUMN><COLUMN NAME=\"LASTNAME\"><![CDATA[TEXT]]></COLUMN><COLUMN NAME=\"FIRSTNAME\"><![CDATA[TEXT]]></COLUMN><COLUMN NAME=\"PHONE\"><![CDATA[TEXT]]></COLUMN></ROW></RESULTS>";
XDocument xmlDocument = XDocument.Parse(msg);
//get the first element named ROW from the xdocument.
var xElement = xmlDocument.Descendants().First(x => x.Name == "ROW");
if (xElement != null)
{
//Loop through the childs of ROW
foreach (var child in xElement.Elements())
{
//Find the first attribute in the child element which is named NAME.
var childAttrName = child.Attributes().First(x => x.Name == "NAME");
//Print the value of the attribute called name and the value of the element.
System.Console.WriteLine(childAttrName.Value + " : " + child.Value);
}
}
Related
I have a XDocument with XML XDocument xdoc1 = XDocument.Load(doc1)
I want to to loop through XML document and if condition is met replace value or node.
I tried code like:
var list = from item in xdoc1.Root.Element("New").Elements() select item;
foreach (XElement item in list)
{
foreach (var node in item.Nodes())
{
if (node.ToString() == "DIV||<Control>")
{
item.Element("Value").Value = "DIV||TextBox";
}
}
But it does not work for me.
If my XML looks like this
<Test>
<New>
<DoSometing>
<Selector>
</Selector>
<Value>DIV||<Control></Value>
</DoSometing>
<DoSometingElse>
<Selector>
</Selector>
<Value>DIV||<Control></Value>
</DoSometingElse>
</New>
</Test>
So my idea is to loop through all the xml and if the condition == <Control> then replace it.
I also tried suff like IEnumerable<XElement> list = from item in xdoc1.Root.Element("New").Elements() where (item.Name == "Value") select item;
You might consider filtering the elements in the query block, and only applying updates to the elements that are necessary. Note that the XElement.Value is being used here, so the decoded element value has to be used.
var list = from item in xdoc1.Root.Element("New").Elements().Elements("Value")
where item.Value == "DIV||<Control>"
select item;
foreach (XElement item in list)
{
item.Value = "DIV||TextBox";
}
Somewhat simpler version.
c#
void Main()
{
const string fileName = #"e:\temp\hala.xml";
const string searchFor = "DIV||<Control>";
const string replaceWith = "789";
//XDocument xdoc = XDocument.Load(fileName);
XDocument xdoc = XDocument.Parse(#" < Test >
<New>
<DoSometing>
<Selector>
</Selector>
<Value>DIV||<Control></Value>
</DoSometing>
<DoSometingElse>
<Selector>
</Selector>
<Value>DIV||<Control></Value>
</DoSometingElse>
</New>
</Test>");
// step #1: find element(s) based on the search value
var xmlFragment = xdoc.Descendants("Value")
.Where(d => d.Value.Equals(searchFor));
// step #2: if found, set its value
foreach (XElement element in xmlFragment)
{
element.SetValue(replaceWith);
}
}
In my code i iterate through an xelement and have it return the value of each node within that element e.g.
foreach(XElement n in XDocument.Descedants("element_name)
{
Console.WriteLine("Searching: " n.Value);
}
My problem is the both <Directory> elements are returned in the string
Searching: C:\Users\215358\OneDrive\MusicC:\Users\215358\Dropbox\Music
My XML file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<Directories>
<Directory>C:\Users\215358\OneDrive\Music</Directory>
<Directory>C:\Users\215358\Dropbox\Music</Directory>
</Directories>
I expect it to output the second line element in <Directory> like this:
C:\Users\215358\Dropbox\Music
Why is this happening?
XElement.Value gets the concatenated text contents of an element. This includes the text of child elements which is not always very helpful. If you just want the text from the current element, you can find the text node in its child nodes.
foreach(XElement n in XDocument.Descedants("Directory"))
{
var text = n.Nodes().Where (x => x is XText).Cast<XText>().FirstOrDefault ();
if(text!=null){
Console.WriteLine("Searching: " + text.Value);
}else{
Console.WriteLine("No text node found");
}
}
Since you want to iterate through each entry and search element value, you could do something like this.
foreach (var element in doc.Descendants("Directory"))
{
if((string)element.Value == "searchstring")
{
// your logic
}
}
In case if you are looking for second element in the xml, you could apply Skip extension to skip specified count of elements.
var secondelement = doc.Descendants("Directory").Skip(1); // Skip first element;
or if you are looking for last element, you could take Last or LastOrDefault extension.
var lastelement = doc.Descendants("Directory").LastOrDefault();
Check this example.
I have an xml file as below
<Games>
<Game>
<name>Tzoker</name>
<file>tzoker1</file>
</Game>
<Game>
<file>lotto770</file>
</Game>
<Game>
<name>Proto</name>
<file>proto220</file>
</Game>
</Games>
I want to get the values of name and file items for every Game node.
It is easy by using this query.
string query = String.Format("//Games/Game");
XmlNodeList elements1 = xml.SelectNodes(query);
foreach (XmlNode xn in elements1)
{
s1 = xn["name"].InnerText;
s2 = xn["file"].InnerText;
}
The problem is that there are some nodes that they don't have the name item. So the code above doesn't work.
I have solved the problem by using the following code
string query = String.Format("//Games/Game/name");
XmlNodeList elements1 = xml.SelectNodes(query);
foreach (XmlNode xn in elements1)
{
s1 = xn.InnerText;
string query1 = String.Format("//Games/Game[name='{0}']/file", s1);
XmlNodeList elements2 = xml.SelectNodes(query1);
foreach (XmlNode xn2 in elements2)
{
s2 = xn2.InnerText;
}
}
The problem is that there is a case that two or more nodes have the same name value. So, the s2 variable will get the file value of the last node that the loop finds. So, I would like to find a way to get the sibling file value of the current name item. How could I do it? I try do move to the parent node of the current node and then to move to the file item but without success by using the following code.
string query = String.Format("//Games/Game/name");
XmlNodeList elements1 = xml.SelectNodes(query);
foreach (XmlNode xn in elements1)
{
s1 = xn.InnerText;
string query1 = String.Format("../file");
XmlNodeList elements2 = xml.SelectNodes(query1);
foreach (XmlNode xn2 in elements2)
{
s2 = xn2.InnerText;
}
}
I hope there is a solution.
You can use Game[name] to filter Game elements to those with child element name. This is possible because child:: is the default axes which will be implied when no explicit axes mentioned. Extending this further to check for child element file as well, would be as simple as Game[name and file] :
string query = String.Format("//Games/Game[name]");
XmlNodeList elements1 = xml.SelectNodes(query);
foreach (XmlNode xn in elements1)
{
s1 = xn["name"].InnerText;
s2 = xn["file"].InnerText;
}
Now to answer your question literally, you can use following-sibling:: axes to get sibling element that follows current context element. So, given the context element is name, you can do following-sibling::file to return the sibling file element.
Your attempt which uses ../file should also work. The only problem was, that your code executes that XPath on xml, the XmlDocument, instead of executing it on current name element :
XmlNodeList elements2 = xn.SelectNodes("../file");
If I understand you correctly you want to find all games that have a name. You can do that using XPath. Here is a solution that uses LINQ to XML. I find that easier to work with than XmlDocument:
var xDocument = XDocument.Parse(xml);
var games = xDocument
.Root
.XPathSelectElements("Game[child::name]")
.Select(
gameElement => new {
Name = gameElement.Element("name").Value,
File = gameElement.Element("file").Value
}
);
The XPath to select all <Game> elements that have a <name> child element is Game[child::name].
I would like to get XmlNodeList from a huge XML file.
Conditions:
I have a List of unique ID values, say IDList
Case I: Collect all the nodes where element called ID has value from IDList.
Case II: Collect all nodes where one of the attribute called idName of element ID has value from IDList.
In short, extract only the nodes which match with the values given in the IDList.
I did this using some loops like load this XML to XmlDocument to iterate over all nodes and ID value but what I am looking for is some sophisticated method to do it faster and in quick way.
Because looping isn't a solution for a large XML file.
My try:
try
{
using (XmlReader reader = XmlReader.Create(URL))
{
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlNodeList nodeList = doc.GetElementsByTagName("idgroup");
foreach (XmlNode xn in nodeList)
{
string id = xn.Attributes["id"].Value;
string value = string.Empty;
if (IDList.Contains(id))
{
value = xn.ChildNodes[1].ChildNodes[1].InnerText; // <value>
if (!string.IsNullOrEmpty(value))
{
listValueCollection.Add(value);
}
}
}
}
}
catch
{}
XML (XLIFF) structure:
<XLIFF>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2">
<file date="2013-07-17">
<body>
<id idName="test_001" >
<desc-group name="test_001">
<desc type="text"/>
</desc-group>
<result-unit idName="test_001_text">
<source>abcd</source>
<result>xyz</result>
</result-unit>
</id>
</body>
</file>
</xliff>
Collect all the nodes like above where idName matches.
EDIT
This is a test that can parse the example you are giving. It attempts to reach the result node directly, so that it stays as efficient as possible.
[Test]
public void TestXPathExpression()
{
var idList = new List<string> { "test_001" };
var resultsList = new List<string>();
// Replace with appropriate method to open your URL.
using (var reader = new XmlTextReader(File.OpenRead("fixtures\\XLIFF_sample_01.xlf")))
{
var doc = new XmlDocument();
doc.Load(reader);
var root = doc.DocumentElement;
// This is necessary, since your example is namespaced.
var nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("x", "urn:oasis:names:tc:xliff:document:1.2");
// Go directly to the node from which you want the result to come from.
foreach (var nodes in idList
.Select(id => root.SelectNodes("//x:file/x:body/x:id[#idName='" + id + "']/x:result-unit/x:result", nsmgr))
.Where(nodes => nodes != null && nodes.Count > 0))
resultsList.AddRange(nodes.Cast<XmlNode>().Select(node => node.InnerText));
}
// Print the resulting list.
resultsList.ForEach(Console.WriteLine);
}
You can extract only those nodes you need by using an XPath query. A brief example on how you 'd go about it:
using (XmlReader reader = XmlReader.Create(URL))
{
XmlDocument doc = new XmlDocument();
doc.Load(reader);
foreach(var id in IDList) {
var nodes = doc.SelectNodes("//xliff/file/body/id[#idName='" + id + "']");
foreach(var node in nodes.Where(x => !string.IsNullOrEmpty(x.ChildNodes[1].ChildNodes[1].InnerText)))
listValueCollection.Add(node.ChildNodes[1].ChildNodes[1].InnerText);
}
}
The xpath expression is of course an example. If you want, you can post an example of your XML so I can give you something more accurate.
I would like to traverse every element and attribute in an xml and grab the name an value without knowing the names of the elements in advance. I even have a book on linq to xml with C# and it only tells me how to query to get the value of elements when I already know the name of the element.
The code below only gives me the most high level element information. I need to also reach all of the descending elements.
XElement reportElements = null;
reportElements = XElement.Load(filePathName.ToString());
foreach (XElement xe in reportElements.Elements())
{
MessageBox.Show(xe.ToString());
}
Elements only walks one level; Descendants walks the entire DOM for elements, and you can then (per-element) check the attributes:
foreach (var el in doc.Descendants()) {
Console.WriteLine(el.Name);
foreach (var attrib in el.Attributes()) {
Console.WriteLine("> " + attrib.Name + " = " + attrib.Value);
}
}
You should try:
reportElements.Descendants()