How to check if first XML node exist? - c#

I have the following XML:
<Root><Node1>node1 value</Node1><Node2>node2 value</Node2></Root>
I'd like to check if Root is the first node. If so, I then want to get the values for the to child nodes.
This XML is inside of an XElement. I've tried this:
xml.Element("Root")
but that returns null. If Root exist, shouldn't it return a non null value?

string xml = #"<Root><Node1>node1 value</Node1><Node2>node2 value</Node2></Root>";
XDocument doc = XDocument.Parse(xml);
var root = doc.Root;
if(root.Name == "Root")
{
foreach(var el in root.Descendants())
{
string nodeValue = el.Value;
}
}
You can check the name of the Root element from Root.Name. After that loop all elements in the root using doc.Root.Descendants().

Since xml is an instance of XElement, it already references the root element, which in this case named Root. Doing xml.Element("Root") will return result only if the <Root> element has another child <Root>.
I'd like to check if Root is the first node.
You can simply check the Name of the root element :
var raw = "<Root><Node1>node1 value</Node1><Node2>node2 value</Node2></Root>";
var xml = XElement.Parse(raw);
if (xml.Name.ToString() == "Root")
Console.WriteLine("Success");
else
Console.WriteLine("Fail");

Try this solution
XDocument doc = XDocument.Parse(#"<Root><Node1>node1value</Node1><Node2>node2value</Node2></Root>");
if(doc!=null)
{
if (doc.Root.Name.LocalName == "Root")
{
foreach (var i in doc.Descendants())
Console.WriteLine(i.Value);
}
}

Related

How to get the sibling of an xml node

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].

Cannot remove empty XML node using XPath expression #"//*[not(node())]"

I have the following node in my xml file :
<PERSON>
<LEOKA_DATA> </LEOKA_DATA>
</PERSON>
I am not able to remove the LEOKA tag using the following code (snippet):
string file = CommonVariables.MainDir + #"\Schemas\RemoveEmptyTags.xsl";
try
{
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(tempFile); //tempfile is the xml file
XmlNodeList emptyElements = xmlDocument.SelectNodes(#"//*[not(node())]");
if (emptyElements != null)
for (int i = emptyElements.Count - 1; i >= 0; i--)
{
var parentNode = emptyElements[i].ParentNode;
if (parentNode != null)
{
if (emptyElements[i].Name != "LINE")
parentNode.RemoveChild(emptyElements[i]);
}
}
}
catch (FileNotFoundException ex)
{ **something here** }
However, the code above works if the node is like below (notice no space between start tag and end tag) :
<LEOKA></LEOKA>
I also tried using the following code but didn't work :
var doc = XDocument.Parse(tempfile);
var emptyElements = from descendant in doc.Descendants()
where string.IsNullOrWhiteSpace(descendant.Value)
select descendant;
emptyElements.Remove();
Any help would be really appreciated. Please let me know if you need more details. Thanks.
I would modify your XPath expression as follows:
XmlNodeList emptyElements = xmlDocument.SelectNodes(#"//*[not(node()[
not(self::text()[normalize-space() = ''])
])]");
In other words, exclude elements that have a child other than an empty text node, where "empty" means having no text value other than whitespace.

How do i get the parent xml based on value of child xml

I have an requirement like,I retrieved id and supplier from an xml which has more than 40 ID's and Suppliers.Now all i need is want to get the parent node of particular Id and Supplier and append it to another xml.
I however managed to retrieve ID and Supplier,now i want to get the whole xml in c#.Any help would be appreciable..
c#
var action = xmlAttributeCollection["id"];
xmlActions[i] = action.Value;
var fileName = xmlAttributeCollection["supplier"];
xmlFileNames[i] = fileName.Value;
This is the code i have used to get ID and supplier.
You may want to be a little more specific about how, you are traversing the Xml Tree, and give your variables types so we can understand the problem more clearly. In saying that here is my answer:
Assuming items[i] is an XmlNode, and in this case we are working with the "hoteId" node, there is a property called XmlNode.ParentNode which returns the immediate ancestor of a node, or null if it is a root node.
XmlNode currentNode = items[i] as XmlNode; //hotelId
XmlNode parentNode = currentNode.ParentNode; //hotelDetail
string outerXml = parentNode.OuterXml; //returns a string representation of the entire parent node
Full example:
XmlDocument doc = new XmlDocument();
doc.Load("doc.xml");
XmlNode hotelIdNode = doc.SelectSingleNode("hoteldetail//hotelId"); //Find a hotelId Node
XmlNode hotelDetailNode = hotelIdNode.ParentNode; //Get the parent node
string hotelDetailXml = hotelDetailNode.OuterXml; //Get the Xml as a string
You can get Parent XML like : XmlNode node = doc.SelectSingleNode("//hoteldetail"); node.innerXml;
I think you'll be better off using linq.
var xDoc = XDocument.Parse(yourXmlString);
foreach(var xElement in xDoc.Descendants("hoteldetail"))
{
//this is your <hoteldetail>....</hoteldetail>
var hotelDetail = xElement;
var hotelId = hotelDetail.Element("hotelId");
//this is your id
var id = hotelId.Attribute("id").Value;
//this is your supplier
var supplier = hotelId.Attribute("supplier").Value;
if (id == someId && supplier == someSupplier)
return hotelDetail;
}

How to get all XML nodes with the same name without knowing their level?

I have a XML Example:
<Fruits>
<Red_fruits>
<Red_fruits></Red_fruits>
</Red_fruits>
<Yellow_fruits>
<banana></banana>
</Yellow_fruits>
<Red_fruits>
<Red_fruits></Red_fruits>
</Red_fruits>
</Fruits>
I have 4 Red_fruits tags, 2 of them shares the same ParentNode (Fruits), I want to get those which have the same ParentNode.
But I just want those which have the same name (Red_fruits), which means Yellow_fruits tag isn't included.
This is the way I am doing right now using C# language:
XmlDocument doc = new XmlDocument();
string selectedTag = cmbX.text;
if (File.Exists(txtFile.text))
{
try
{
//Load
doc.Load(cmbFile.text);
//Select Nodes
XmlNodeList selectedNodeList = doc.SelectNodes(".//" + selectedTag);
}
Catch
{
MessageBox.show("Some error message here");
}
}
This is returning me all red_fruits, not just the ones that belongs to Fruits.
I can't make XmlNodeList = doc.SelectNodes("/Fruits/Red_fruits") because I want to use this code to read random XML files, so I don't know the exact name that specific node will have, I just need to put all nodes with the same name and same level into a XmlNodeList using C# Language.
Is there a way of achieve this without using LINQ? How to do that?
An understanding on the usage of Single Slash / and Double slash // can help here.
Let's see how / and // work in relation to the root node. When / is used at the beginning of a path:
/a
it will define an absolute path to node a relative to the root. As such, in this case, it will only find a nodes at the root of the XML tree.
When // is used at the beginning of a path:
//a
it will define a path to node a anywhere within the XML document. As such, in this case, it will find a nodes located at any depth within the XML tree.
These XPath expressions can also be used in the middle of an XPath value to define ancestor-descendant relationships. When / is used in the middle of a path:
/a/b
it will define a path to node b that is an immediate direct descendant (ie. a child) of node a.
When // used in the middle of a path:
/a//b
it will define a path to node b that is ANY descendant of node a.
Coming back to your question:
// using GetElementsByTagName() return all the Elements having name: Red_Fruits
XmlDocument doc = new XmlDocument();
XmlNodeList nodes= doc.GetElementsByTagName("Red_Fruits");
//Using SelectNodes() method
XmlNodelist nodes = doc.SelectNodes("//Fruits/Red_Fruits");
// This will select all elements that are children of the <Fruits> element.
In case <Fruits> is the root element use the Xpath: /Fruits/Red_Fruits. [ a single slash /]
If you're simply trying to find the "next" or "previous" iteration of a single node, you can do the following and then compare it to the name
XmlNode current = doc.SelectSingleNode("Fruits").SelectSingleNode("Red_fruits");
XmlNode previous = current.NextSibling;
XmlNode next = current.NextSibling;
and you can iterate until you find the proper sibling
while(next.Name != current.Name)
{
next = next.NextSibling;
}
or you can even get your list by invoking the 'Parent' property
XmlNodeList list = current.ParentNode.SelectNodes(current.Name);
Worst case scenario, you can cycle through the XMLNode items in selectedNodeList and check the ParentNode properties. If necessary you could go recursive on the ParentNode check and count the number of times it takes to get to the root node. This would give you the depth of a node. Or you could compare the ParentNode at each level to see if it is the parent you are interested in, if that parent is not the root.
public void Test(){
XmlDocument doc = new XmlDocument();
string selectedTag = cmbX.text;
if (File.Exists(txtFile.text))
{
try
{
//Load
doc.Load(cmbFile.text);
//Select Nodes
XmlNodeList selectedNodeList = doc.SelectNodes(".//" + selectedTag);
List<XmlNode> result = new List<XmlNode>();
foreach(XmlNode node in selectedNodeList){
if(depth(node) == 2){
result.Add(node);
}
}
// result now has all the selected tags of depth 2
}
Catch
{
MessageBox.show("Some error message here");
}
}
}
private int depth(XmlNode node) {
int depth = 0;
XmlNode parent = node.ParentNode;
while(parent != null){
parent = node.ParentNode;
depth++;
}
return depth;
}

XElement value in C#

How to get a value of XElement without getting child elements?
An example:
<?xml version="1.0" ?>
<someNode>
someValue
<child>1</child>
<child>2</child>
</someNode>
If i use XElement.Value for <someNode> I get "somevalue<child>1</child><child>2<child>" string but I want to get only "somevalue" without "<child>1</child><child>2<child>" substring.
You can do it slightly more simply than using Descendants - the Nodes method only returns the direct child nodes:
XElement element = XElement.Parse(
#"<someNode>somevalue<child>1</child><child>2</child></someNode>");
var firstTextValue = element.Nodes().OfType<XText>().First().Value;
Note that this will work even in the case where the child elements came before the text node, like this:
XElement element = XElement.Parse(
#"<someNode><child>1</child><child>2</child>some value</someNode>");
var firstTextValue = element.Nodes().OfType<XText>().First().Value;
There is no direct way. You'll have to iterate and select. For instance:
var doc = XDocument.Parse(
#"<someNode>somevalue<child>1</child><child>2</child></someNode>");
var textNodes = from node in doc.DescendantNodes()
where node is XText
select (XText)node;
foreach (var textNode in textNodes)
{
Console.WriteLine(textNode.Value);
}
I think what you want would be the first descendant node, so something like:
var value = XElement.Descendents.First().Value;
Where XElement is the element representing your <someNode> element.
You can specifically ask for the first text element (which is "somevalue"), so you could also do:
var value = XElement.Descendents.OfType<XText>().First().Value;

Categories