How can I get all the nodes of a xml file? - c#

Let's say I have this XML file:
<Names>
<Name>
<FirstName>John</FirstName>
<LastName>Smith</LastName>
</Name>
<Name>
<FirstName>James</FirstName>
<LastName>White</LastName>
</Name>
</Names>
And now I want to print all the names of the node:
Names
Name
FirstName
LastName
I managed to get the all in a XmlNodeList, but I dont know how SelectNodes works.
XmlNodeList xnList = xml.SelectNodes(/*What goes here*/);
I want to select all nodes, and then do a foreach of xnList (Using the .Value property I assume).
Is this the correct approach? How can I use the selectNodes to select all the nodes?

Ensuring you have LINQ and LINQ to XML in scope:
using System.Linq;
using System.Xml.Linq;
If you load them into an XDocument:
var doc = XDocument.Parse(xml); // if from string
var doc = XDocument.Load(xmlFile); // if from file
You can do something like:
doc.Descendants().Select(n => n.Name).Distinct()
This will give you a collection of all distinct XNames of elements in the document. If you don't care about XML namespaces, you can change that to:
doc.Descendants().Select(n => n.Name.LocalName).Distinct()
which will give you a collection of all distinct element names as strings.

There are several ways of doing it.
With XDocument and LINQ-XML
foreach(var name in doc.Root.DescendantNodes().OfType<XElement>().Select(x => x.Name).Distinct())
{
Console.WriteLine(name);
}
If you are using C# 3.0 or above, you can do this
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();

Add
using System.Xml.Linq;
Then you can do
var element = XElement.Parse({Your xml string});
Console.Write(element.Descendants("Name").Select(el => string.Format("{0} {1}", el.Element("FirstName").Value, el.Element("LastName").Value)));

Related

How can I get a list of XML nodes by value using C#

I'm trying to get a XmlNodeList from an XmlDocument for nodes that have a certain value, with a view to removing those nodes.
XML:
<List xmlns="http://mynamespace.com/v1">
<Category>2144</Category>
<Title>My Object</Title>
<StartPrice>30.00</StartPrice>
<ReservePrice>-999</ReservePrice>
<BuyNowPrice>-999</BuyNowPrice>
</List>
Preferably I don't want to iterate through every node and check its value. I looked at trying to use LINQ from some examples but I just don't understand it enough to even attempt it.
I feel I'm getting close-ish with XPath (https://www.w3schools.com/xml/xpath_syntax.asp) but I'm beginning to think what I want to do isn't supported.
string xml = UtilityClass.SerializeObject<Listing> ( myListing);
XmlDocument xmlDocument = new XmlDocument ();
xmlDocument.LoadXml ( xml );
XmlElement root = xmlDocument.DocumentElement;
XmlNodeList nodes = root.SelectNodes ( "//*['-999']" );
Am open to other suggestions to get the same result, i.e. remove the nodes with -999 from the Xml document.
Thanks in advance
LINQ to XML is preferred API while dealing with XML in .Net Framework since 2007.
Check it out how easy to achieve what you need in one single statement.
LINQ methods are chained one after another and self-explanatory:
Get all descendants of the root node, taking into account a default namespace.
Whatever the names of the elements.
Where element value is -999.
Convert them to a List<>.
Remove those elements from the XML document.
c#
void Main()
{
XDocument xdoc = XDocument.Parse(#"<List xmlns='http://mynamespace.com/v1'>
<Category>2144</Category>
<Title>My Object</Title>
<StartPrice>30.00</StartPrice>
<ReservePrice>-999</ReservePrice>
<BuyNowPrice>-999</BuyNowPrice>
</List>");
XNamespace ns = xdoc.Root.GetDefaultNamespace();
xdoc.Descendants(ns + "List")
.Elements()
.Where(x => x.Value.Equals("-999"))
.ToList()
.ForEach(x => x.Remove());
Console.WriteLine(xdoc);
}
Output
<List xmlns="http://mynamespace.com/v1">
<Category>2144</Category>
<Title>My Object</Title>
<StartPrice>30.00</StartPrice>
</List>

XML - where node has same name but different values

I am trying to read an xml file (and later import the data in to a sql data base) which contains employees names address' etc.
The issue I am having is that in the xml the information for the address for the employee the node names are all the same.
<Employee>
<EmployeeDetails>
<Name>
<Ttl>Mr</Ttl>
<Fore>Baxter</Fore>
<Fore>Loki</Fore>
<Sur>Kelly</Sur>
</Name>
<Address>
<Line>Woof Road</Line>
<Line>Woof Lane</Line>
<Line>Woofington</Line>
<Line>London</Line>
</Address>
<BirthDate>1985-09-08</BirthDate>
<Gender>M</Gender>
<PassportNumber>123756rt</PassportNumber>
</EmployeeDetails>
</Employee>
I all other items are fine to extract and I have tried to use Linq to iterate through each "Line" node but it always just gives be the first Line and not the others.
var xAddreesLines = xEmployeeDetails.Descendants("Address").Select(x => new
{
address = (string)x.Element("Line").Value
});
foreach (var item in xAddreesLines)
{
Console.WriteLine(item.address);
}
I need to able to when I'm importing to my sql db that address line is separate variable
eg
var addressline1 = first <line> node
var addressline2 = second <line> node etc etc.
Any advice would be most welcome.
This should give you the expected output:-
var xAddreesLines = xdoc.Descendants("Address")
.Elements("Line")
.Select(x => new { address = (string)x });
You need to simply fetch the Line elements present inside Address node and you can project them. Also note there is no need to call the Value property on node when you use explicit conversion.
You can do it like this:
using System.Xml;
.
.
.
XmlDocument doc = new XmlDocument();
doc.Load("source.xml");
// if you have the xml in a string use doc.LoadXml(stringvar)
XmlNamespaceManager nsmngr = new XmlNamespaceManager(doc.NameTable);
XmlNodeList results = doc.DocumentElement.SelectNodes("child::Employee", nsmngr);
foreach (XmlNode result in results)
{
XmlNode namenode = result.SelectSingleNode("Address");
XmlNodeList types = result.SelectNodes("line");
foreach (XmlNode type in types)
{
Console.WriteLine(type.InnerText);
}
XmlNode fmtaddress = result.SelectSingleNode("formatted_address");
}
Refer to this question for the original source.

Select last XML node

I have this XML code:
<AriaGostarInformation>
<MenuInformation>
<MenuNames Name="0" href="default.aspx">home</MenuNames>
<SubMenuNames parentName="1">
fgfgfgfgs
</SubMenuNames>
<SubMenuNames parentName="3">
</SubMenuNames>
</MenuInformation>
<SliderInformation>
<SliderImageAddress>..\..\Img\Hydrangeas.jpg,</SliderImageAddress>
<SliderImageAddress>..\..\Img\Jellyfish.jpg,</SliderImageAddress>
<SliderImageAddress>..\..\Img\Koala.jpg,</SliderImageAddress>
<SliderImageAddress>..\..\Img\Lighthouse.jpg,</SliderImageAddress>
<SliderImageAddress>..\..\Img\Penguins.jpg,</SliderImageAddress>
<SliderImageAddress>..\..\Img\Tulips.jpg,</SliderImageAddress>
</SliderInformation>
<LastProductInformation>
<Product Name="147">
<Subject>
</Subject>
<ProductImageAddress>http://localhost:1209/ckeditor/plugins/imagebrowser/browser/Hydrangeas.jpg</ProductImageAddress>
<ProductDes>
<p><span style="color:#FFA07A;">qwqweqweqe</span>qwe</p>
<p><span style="font-size:11px;">qweqweqw</span>e</p>
</ProductDes>
</Product>
<Product Name="dsa">
<Subject>salm</Subject>
<ProductImageAddress>http://localhost:1209/ckeditor/plugins/imagebrowser/browser/Hydrangeas.jpg</ProductImageAddress>
<ProductDes>
<p>sdADASDASDASDASDASDASD</p>
<p>ASDASDASDADASDASDASDASDA</p>
<p>ASDASDASDASDASDASDASDASDASD</p>
</ProductDes>
</Product>
</LastProductInformation>
</AriaGostarInformation>
I want select last product node in LastProductInformation and get this node's attribute.
My code is:
XmlDocument xdoc = new XmlDocument();
xdoc.Load(AppDomain.CurrentDomain.BaseDirectory + #"\static\css\xml\data.xml");
XmlNode xparent = xdoc.SelectSingleNode("//LastProductInformation");
var b = xparent.SelectSingleNode("/Product[last()]").Attributes["Name"].Value;
but this returns null. What should I do?
Using LINQ to XML
var value = XDocument.Load("path")
.Descendants("Product")
.Last()
.Attribute("Name").Value;
Also you can use XPath with LINQ to XML
var value = XDocument.Load("path")
.XPathSelectElement("//LastProductInformation/Product[last()]")
.Attribute("Name").Value;
Note: Make sure you have a reference to System.Xml.Linq namespace from your project.
You don't have to change to linq.
var b = xparent.SelectSingleNode("//Product")[last()].Attributes["Name"].Value;
The last() works like an index so should be at the end.

Unable to remove root node from an xml document using linq to xml c#

Actullay, I need to get all elements except root node from first xml document and so that I could insert them as child nodes to an element(that has same name as a previous doc's root name) in a new document.
So I have tried various ways to achieve it, one of them is removing the root node of first and then trying to add elements to a new one's as given below:
I have tried the following but could not achieve it.
XDocument testDoc = XDocument.Parse(Mydocument);
testDoc.Descendants().Where(e => e.Name.LocalName == "rootName").Select(m=>m).Single().Remove();
var resultDoc = testDoc;
The above code is giving me an empty "{}" result.
my xml document looks something like the below one's:
<rootName xsi:schemaLocation="" xmlns:xsi="" xmlns="">
<main>
<child>
</child>
<anotherchild>
</anotherchild>
</main>
</rootName>
And another way is getting all the elements of first document as the following:
var resultDoc = testDoc.Descendants(ns + "rootName").Elements();
the above statement is giving me the list of elements in the "testDoc" which
I need to do something like below, I am clueless:
<AnotherDocument xsi:schemaLocation="" xmlns:xsi="" xmlns="">
<firstNode>
<rootName>
<main>
<child>
</child>
<anotherchild>
</anotherchild>
</main>
</rootName>
</firstNode>
Please let me know how to insert those elements in a new document as above if I am correct else let me know the way to resolve this issue.
Thanks in advance.
You can replace content of rootName element in another document with elements from first document root:
var xDoc = XDocument.Parse(Mydocument);
var anotherXDoc = XDocument.Load("anotherdata.xml");
XNamespace ns = "http://..."; // your xml namespance
var rootName = anotherXDoc.Descendants(ns + "rootName").First();
rootName.ReplaceNodes(xDoc.Root.Elements());
By this page_nodes gets all nodes now you can used all node by for each loop
var page_nodes = from p in xdoc.Descendants.Where(e => e.Name.LocalName == "rootName").Select(m=>m).Single().Remove() select p;
foreach (var page_node in page_nodes)
{
//Do stuff
}
Wouldn't removing a root node, remove all its child nodes as well? The result you are getting is to be expected I think. You should probably get all the children of the root and copy them to your new document.

Get certain xml node and save the value

Considering the following XML:
<Stations>
<Station>
<Code>HT</Code>
<Type>123</Type>
<Names>
<Short>H'bosch</Short>
<Middle>Den Bosch</Middle>
<Long>'s-Hertogenbosch</Long>
</Names>
<Country>NL</Country>
</Station>
</Stations>
There are multiple nodes. I need the value of each node.
I've got the XML from a webpage (http://webservices.ns.nl/ns-api-stations-v2)
Login (--) Pass (--)
Currently i take the XML as a string and parse it to a XDocument.
var xml = XDocument.Parse(xmlString);
foreach (var e in xml.Elements("Long"))
{
var stationName = e.ToString();
}
You can retrieve "Station" nodes using XPath, then get each subsequent child node using more XPath. This example isn't using Linq, which it looks like you possibly are trying to do from your question, but here it is:
XmlDocument xml = new XmlDocument();
xml.Load(xmlStream);
XmlNodeList stations = xml.SelectNodes("//Station");
foreach (XmlNode station in stations)
{
var code = station.SelectSingleNode("Code").InnerXml;
var type = station.SelectSingleNode("Type").InnerXml;
var longName = station.SelectSingleNode("Names/Long").InnerXml;
var blah = "you should get the point by now";
}
NOTE: If your xmlStream variable is a String, rather than a Stream, use xml.LoadXml(xmlStream); for line 2, instead of xml.Load(xmlStream). If this is the case, I would also encourage you to name your variable to be more accurately descriptive of the object you're working with (aka. xmlString).
This will give you all the values of "Long" for every Station element.
var xml = XDocument.Parse(xmlStream);
var longStationNames = xml.Elements("Long").Select(e => e.Value);

Categories

Resources