Reader Nodes from XML - c#

I have this XML and i try to read the scpefic nodes but not work =(
the my code is:
XmlDocument doc = new XmlDocument();
doc.Load("https://apps.db.ripe.net/whois/search.xml?query-string=193.200.150.125&source=ripe");
XmlNode node = doc.SelectSingleNode("/whois-resources/objects/attributes/descr");
MessageBox.Show(node.InnerText);
the two circled values on image
Url: https://apps.db.ripe.net/whois/search.xml?query-string=193.200.150.125&source=ripe
it is possible?

When you are looking for a node which has an attribute "name" set to a particular value, you need to use different syntax.
You're looking for something like:
XmlNode node = doc.SelectSingleNode("/whois-resources/objects/object/attributes/attribute[#name=\"descr\"]");
XmlAttribute attrib = node.Attributes["value"];
MessageBox.Show(attrib.Value);
This will select your second node example, get the value of the value attribute, and display it.

How about using Linq To Xml?
var xDoc = XDocument.Load("https://apps.db.ripe.net/whois/search.xml?query-string=193.200.150.125&source=ripe");
var desc = xDoc.Descendants("attribute")
.Where(a => (string)a.Attribute("name") == "descr")
.Select(a => a.Attribute("value").Value)
.ToList();
or
var desc = xDoc.XPathSelectElements("//attribute[#name='descr']")
.Select(a => a.Attribute("value").Value)
.ToList();

Related

Retrieve processing instructions using XDocument

I have an XML document containing processing instructions. I know that, with the XmlDocument class, you can use
var node = xmlDoc.SelectSingleNode("processing-instruction('xml-stylesheet')") as XmlProcessingInstruction;
but I want to use XDocument. How can I do this?
This is how I access an XML file's nodes with the XDocument class.
However, you'll have to be more specific on what you want to do with it.
XDocument doc = XDocument.Load("filepath");
var node = doc.Nodes().OfType<XElement>().SingleOrDefault(n => n.Name == "node name");
var node_value = node.Value;
var node_descendants = node.Descendants();
UPDATE:
As you may have noticed there's no SelectSingleNode in XDocument, in fact, to retrieve the node you want you'll have to fetch it from the corresponding ienumerable collection, or alternatively from the predefined FirstNode, NextNode, PreviousNode, LastNode, but you cannot apply any filters to those. Therefore the only ways to retrieve ProcessingInstruction nodes are
var pI_nodes = doc.Nodes().OfType<XProcessingInstruction>();
And
var pI_nodes = (from node in doc.Nodes()
where node.NodeType == System.Xml.XmlNodeType.ProcessingInstruction
select node);
If you expect to retrieve several ProcessingInstructions and need to filter these as well, the equivalent to the node name would the Target property
var filtered_pIs = pI_nodes_1.Where(pI => pI.Target == "xml-stylesheet");
And as a final reminder the value of the processing instruction is stored in the Data property.
string pI_value = filtered_pIs.First().Data
Here is one way:
var node = xDoc.Root.Nodes().OfType<XProcessingInstruction>().First();

C# split xml innertext or parse innerxml

I have an XML file with a structure similar to this
<entry name="something">
<members>
<member>aaa</member>
<member>bbb</member>
</members>
</entry>
<entry name="something_else">
<members>
<member>ccc</member>
<member>ddd</member>
</members>
</entry>
I need to be able to get the values out of each of the member nodes to store in a datatable. if i use the innertext property, it concatenates the values (aaabbb). there is nothing discernible to split the string on. I can also use the inner XML but then i just get a string with the XML structure (aaa bbb<\member>)
What is the best way to get each value out of the XML elements and store it in a string array?
here is what I have been trying.
foreach (XmlNode grpNode in GrpList)
{
subNode = grpNode.Attributes["name"];
if (subNode != null)
{
Obj = grpNode.Attributes["name"].Value;
}
subNode = grpNode["members"];
if (subNode != null)
{
string innerXml = string.Empty;
innerXml = grpNode["members"].InnerXml.ToString();
string[] tempArrary = innerXml.Split(new char[] {'>', '<'});
}
}
You can use Xpath to iterate through Entry nodes and get the members within it like this
string xml = "<root><entry name='something'>" +
"<members>" +
"<member>aaa</member>" +
"<member>bbb</member>" +
"</members>" +
"</entry>" +
"<entry name='something_else'>" +
"<members>" +
"<member>ccc</member>" +
"<member>ddd</member>" +
"</members>" +
"</entry></root>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var memsList = doc.SelectNodes("//entry");
foreach (XmlNode a in memsList)
{
Console.WriteLine(a.Attributes["name"].Value);
var memList = a.SelectNodes("members/member");
foreach(XmlNode x in memList)
Console.WriteLine(x.InnerText);
}
You need to iterate the child elements within members, so something like:
foreach (var node in grpNode["members"].ChildNodes)
{
var value = node.InnerText;
}
That said, you would be better off using LINQ to XML unless you have some specific reason to use XmlDocument. This gives you much more expressive code, for example:
var doc = XDocument.Parse(xml);
var something = doc.Descendants("entry")
.Where(e => (string)e.Attribute("name") == "something")
.Single();
var somethingMembers = something.Descendants("member")
.Select(e => e.Value)
.ToArray();
This should do the trick:
XDocument xdoc = XDocument.Load(#"Path/to/file");
var result = xdoc.Descendants("member").Select (x => x.Value).ToArray();
Result:
Demo Code
the xml you've provided isn't valid. But assuming you just want the inner text of all member nodes into a string array, I'd just use Linq-To-Xml (XDocument):
var results = XDocument.Parse(xmlString)
.Descendants("member")
.Select(m => m.Value)
.ToArray();
Even though you're using the old XmlDocument API, by throwing in an .OfType<XmlNode>() you can convert an XmlNodeList to a generic enumerable and thereby mix in some linq and lambda syntax, for instance:
var tempArrary = subNode.SelectNodes("member").OfType<XmlNode>().Select(n => n.InnerText).ToArray();

Selecting a child node having specific value

I want to check that if the "< city>" node 'having a specific value (say Pathankot )' already exist in the xml file under the a particular "< user Id="any"> having a specific Id", before inserting a new city node into the xml.
< users>
< user Id="4/28/2015 11:29:44 PM">
<city>Fazilka</city>
<city>Pathankot </city>
<city>Jalandher</city>
<city>Amritsar</city>
</user>
</users>
In order to insert I am using the Following c# code
XDocument xmlDocument = XDocument.Load(#"C:\Users\Ajax\Documents\UserSelectedCity.xml");
string usrCookieId = Request.Cookies["CookieId"].Value;
xmlDocument.Element("Users")
.Elements("user")
.Single(x => (string)x.Attribute("Id") == usrCookieId)
//Incomplete because same named cities can be entered more that once
//need to make delete function
.Add(
new XElement("city", drpWhereToGo.SelectedValue));
My Questions:
How Can i check weather the < city> node having specific value say
Pathankot already exist in the xml file Before Inserting a new city
node.
I am Using absolute Path in" XDocument xmlDocument =
XDocument.Load(#"C:\Users\Ajax\Documents\Visual Studio
2012\WebSites\punjabtourism.com\UserSelectedCity.xml");" This
does not allow me to move the files to new folder without changing
the path which is not desirable. But if i use the relative path The
Error Occures "Access Denied";
I would use this simple approach:
var query =
xmlDocument
.Root
.Elements("user")
.Where(x => x.Attribute("Id").Value == usrCookieId)
.Where(x => !x.Elements("city").Any(y => y.Value == "Pathankot"));
foreach (var xe in query)
{
xe.Add(new XElement("city", drpWhereToGo.SelectedValue));
}
It's best to avoid using .Single(...) or .First(...) if possible. The description of your problem doesn't sound like you need to use these though.
Try this:-
First load the XML file into XDocument object by specifying the physical path where your XML file is present. Once you have the object just take the First node with matching condition (please note I am using First instead of Single cz you may have multiple nodes with same matching condition, Please see the Difference between Single & First)
XDocument xmlDocument = XDocument.Load(#"YourPhysicalPath");
xmlDocument.Descendants("user").First(x => (string)x.Attribute("Id") == "1"
&& x.Elements("city").Any(z => z.Value.Trim() == "Pathankot"))
.Add(new XElement("city", drpWhereToGo.SelectedValue));
xmlDocument.Save("YourPhysicalPath");
Finally add the required city to the node retrieved from the query and save the XDocument object.
Update:
If you want to check first if all the criteria fulfills then simply use Any like this:-
bool isCityPresent = xdoc.Descendants("user").Any(x => (string)x.Attribute("Id") == "1"
&& x.Elements("city").Any(z => z.Value.Trim() == "Pathankot"));
I'd create an extension to clean it up a bit, and use XPath for the search.
public static class MyXDocumentExtensions
{
public static bool CityExists(this XDocument doc, string cityName)
{
//Contains
//var matchingElements = doc.XPathSelectElements(string.Format("//city[contains(text(), '{0}')]", cityName));
//Equals
var matchingElements = doc.XPathSelectElements(string.Format("//city[text() = '{0}']", cityName));
return matchingElements.Count() > 0;
}
}
And call it like that:
XDocument xmlDocument = XDocument.Load("xml.txt");
var exists = xmlDocument.CityExists("Amritsar");
Expanding on your question in the comment, you can then use it as:
if(!xmlDocument.CityExists("Amritsar"))
{
//insert city
}
If you would like to match regardless of the trailing whitespace in the XML, you can wrap the text() call in XPath with a normalize-space:
var matchingElements = doc.XPathSelectElements(string.Format("//city[normalize-space(text()) = '{0}']", cityName.Trim()));

Select Node Type From XML document

Hi i have a scenario where i want to search the node in xml file and identify the type of file.
XDocument xDococumnetObj = XDocument.Load(filePath);
XElement presentationElement=
xDococumnetObj.Descendants()
.Where(x => x.Name.LocalName.Equals("collegge"))
.FirstOrDefault();
I have written query which returns me collegge node. But i just want to identify the type of document it is. I want to identify the document whether it contains {"Collegge","University","Company","Banking"} in single query and return its Type only.
string[] docTypes = {"Collegge", "University", "Company", "Banking"};
XDocument xdoc = XDocument.Load(filePath);
var docType = docTypes.FirstOrDefault(type =>
xdoc.Descendants().Any(n => n.Name.LocalName == type.ToLower()));
UPDATE: If all elements declared in same namespace, you can use following code to avoid traversing all elements from files
string[] docTypes = {"Collegge", "University", "Company", "Banking"};
XDocument xdoc = XDocument.Load(filePath);
XNamespace ns = "http://www.foo.org/2013/bar";
var docType = docTypes.FirstOrDefault(type => xdoc.Descendants(ns + type).Any());

create if statements blocks based on the value of an XML element

How can i create if statements blocks based on the value of id (XML element)
string filepath = Server.MapPath("XMLFile2.xml");
XmlDocument xdoc1 = new XmlDocument();
xdoc1.Load(filepath);
XmlNode root = xdoc1.DocumentElement;
XmlNode idNode = root.SelectSingleNode("/students/student/id");
if (idNode.Value == 1.ToString()){my code}
im afraid that this code selects the first node in the file,,, or this there another way i can select the node based on its id value????
Replace your this code
Previous code
XmlNode idNode = root.SelectSingleNode("/students/student/id");
New code
XmlNode idNode = root.SelectSingleNode("//students/student/id");
And ya mostly if you want to search node base on the value of id than use following.
XmlNode idNode = root.SelectSingleNode("//students/student/[id='"+<YOUR id>+"']");
It will work...
You can use LINQ2XML
XElement doc =XElement.Load(filepath);
var xpath = String.Format("//students/student/[id='{0}']", "1");
-
|->your ID value goes here
var StudentNodeWithID1= doc.XPathSelectElement(xpath);
//selects a single student node with id as 1 or would return NULL if there are no students with id as 1
OR
var StudentNodeWithID1= doc.Elements("student")
.Where(s => s.Element("id").Value == "1")
.SingleOrDefault();
StudentNodeWithID1.Element("id");//id node
StudentNodeWithID1.Element("id").Value;//id value

Categories