I'm working on a C#/ASP.Net project.
Let's say this is an xml document:
parent1
child1 attributeA
child2 attributeA
parent2
child3 attributeA
child4 attributeB
I want to navigate with next and previous buttons between anything with attributeA, so if I'm at parent1/child2, next would be parent2/child3 and previous would be parent1/child1.
I can create a new XML Document, I can load it, and I can get the current node, but I don't know about next and previous.
How can I do that? Haven't done xpaths in a while. A LONG while. I looked around here for something similar but either it's not there or I can't find it.
Can anyone help?
The MSDN has a nice article about XPaths with great examples
But this code should give you all the nodes that have attributeA regardless of where they are nested in the XML:
var doc = new XmlDocument();
doc.Load(#"C:\path\to\file.xml");
XmlNodeList nodes = doc.SelectNodes("//*[#attributeA]");
foreach (var node in nodes)
{
// your code here
}
The path //*[#attributeA] boils down to:
// "one or more levels deep"
* "any element"
[#attributeA] "with attribute 'attributeA'"
Related
Here is my Project Folder Structure into Tree Structure
(*)Root
[]English
[1]Novel
[2]Thriller
[2.1]Happy
[2.1.1]Life Happy
HappyInLife
LoveInLife
[2.1.2]Joy
everywhereJoy
[2.1.3]Lauging
Always
Sometimes
Never
[2.2]Sad
[2.3]Excited
[2.4]Alone
[3]Love Story
[4]Action
[]Hindi
[]Marathi
Now here in the above structure I am at node [2.4]Alone
and I want to traverse at node [2.1]Happy. Further I want to access all children , sub children and sub .... of node [2.1] Happy.
My Project requirement is to display the node [2.1]Happy along with all its children and sub children and so on.... from the node [2.4]Alone
My Work up till now (I am at node [2.4]Alone)
var home=#Model.Parent.Children.First();
So home will have the node [2.1]Happy inside it.
but the problem is it will give me only the children of [2.1]Happy and not its Children's children and so on...
I tired using #Model.AncestorsOrSelf(3);
but not able to achieve my target .
Any help is appreciated
I suggest using uQuery: (1) (2)
Code would look like:
#using umbraco
var current = umbraco.NodeFactory.Node.GetCurrent();
var your21Happy = current.Parent.GetChildNodes().First(); // or the way you was getting it already.
var descendants = your21Happy.GetDescendantNodes();
uQuery is pretty flexible, you can filter queried nodes by anything, like
.GetDescendantNodesByType("uBlogsyPost")
or
.GetDescendantNodes(x => x.WriterName == "admin")
etc.
I have xml document like this:
<level1>
<level2>
<level3>
<attribute1>...</attribute1>
<attribute2>false</attribute2>
<attribute3>...</attribute3>
</level3>
<level3>
<attribute1>...</attribute1>
<attribute2>true</attribute2>
<attribute3>...</attribute3>
</level3>
</level2>
<level2>
<level3>
<attribute1>...</attribute1>
<attribute2>false</attribute2>
...
...
...
I'm using c#, and I want to go thru all "level3", and for every "level3", i want to read attribute2, and if it says "true", i want to print the corresponding attribute3 (can be "level3" without these attributes).
I keep the xml in XmlDocument.
Then I keep all the "level3" nodes like this:
XmlNodeList xnList = document.SelectNodes(String.Format("/level1/level2/level3"));
(document is the XmlDocument).
But from now on, I don't know exactly how to continue. I tried going thru xnList with for..each, but nothing works fine for me..
How can I do it?
Thanks a lot
Well I'd use LINQ to XML:
var results = from level3 in doc.Descendants("level3")
where (bool) level3.Element("attribute2")
select level3.Element("attribute3").Value;
foreach (string result in results)
{
Console.WriteLine(result);
}
LINQ to XML makes all kinds of things much simpler than the XmlDocument API. Of course, the downside is that it requires .NET 3.5...
(By the way, naming elements attributeN is a bit confusing... one would expect attribute to refer to an actual XML attribute...)
You can use LINQ to XML and reading this is a good start.
You can use an XPath query. This will give you a XmlNodeList that contains all <attribute3> elements that match your requirement:
var list = document.SelectNodes("//level3[attribute2 = 'true']/attribute3");
foreach(XmlNode node in list)
{
Console.WriteLine(node.InnerText);
}
You can split the above xpath query in three parts:
"//level3" queries for all descendant elements named <level3>.
"[attribute2 = 'true']" filters the result from (1) and only keeps the elements where the child element <attribute2> contains the text true.
"/attribute3" takes the <attribute3> childnode of each element in the result of (2).
I have a heavier XML file with lots and lots of tree nodes. I need to pick-up some particular node (for example say Diet), under which there are multiple sections.
ie. Diet node occurs randomly in the XML, so i need to find the node as Diet and get its child elements and save it to DB.
Assume that Diet is not only one line, it has 10-12 entries underneath it (may be i can get its contents using InnerXML, but really can't get line by line nodes)
Make sure you have added a reference to "System.xml.Linq'.
Suck out all the Diet elements:
XElement wholeFile = XElement.Load(#"C:\DietSampleXML.xml");
IEnumerable<XElement> dietElements = wholeFile.Descendants("Diet");
If you set a breakpoint and hover the mouse over "dietElements" and click "Results View", you will see all the Diet elements and their inner xml.
Now iterate through dietElements to add each element and/or children to your database: "foreach (XElement x in dietElements) { ... }"
I tested this with the following xml:
<?xml version="1.0" encoding="utf-8" ?>
<TestElement>
<Diet>
<Name>Atkins</Name>
<Colories>1000</Colories>
</Diet>
<TestElement2>
<Diet>
<Name>Donuts Only</Name>
<Calories>1500</Calories>
</Diet>
</TestElement2>
<TestElement3>
<TestElement4>
<Diet>
<Name>Vegetarian</Name>
<Calories>500</Calories>
</Diet>
</TestElement4>
</TestElement3>
</TestElement>
Depending on the structure of your XML file, you might try loading it into a DataSet (DataSet.ReadXML()) and see what DataTable it puts your Diet nodes into ... if it parses it ok then it is pretty simple to loop through the DataTable and get all your Diet node values.
I wrote a little toy app that opens XML like that, listing all the DataTables in a tree view then showing the table content in a grid. The VS project file for it is here or just an MSI to install it is here, if you want to see how a DataSet parses your XML file.
In XPath, it's just //Diet
To say more, I'd need to know more about your environment.
var doc = XDocument.Load("yourfile.xml");
var nodes = from d in doc.Desendants("Diet")
select d;
foreach(var node in nodes)
{ // do stuff with node
}
The pseudo code below, contains the XPath statement that would get you all elements who have a 'Diet' as parent. Since it produces a XmlNodeList you can walk every node and save it to the DB. For performance i would consider consolidating what you want to save, and then save it, not per line (round trip for every entry is sub-optimal)
XmlNodeList list = xDoc.DocumentElement.SelectNodes("//*[parent::Diet]");
foreach (XmlNode entry in list)
{
DAL.SaveToDatabase(entry);
}
Hope this helps,
Sample XML
<A>
<B>
<B1/>
<B2/>
<B3/>
<B4/>
<B5/>
</B>
<C>
<C1/>
<C2/>
<C3/>
<C4/>
<C5/>
</C>
</A>
Query:
C#
When I read the the child nodes of A it retuns nodes B & C with their child nodes.
Is there any possibility so that I can get only B & C without their respective child nodes
I need to populate the tree with this type of xml & the xml file is quite big. so I need to load the childs at the time of expanding any node
Requirement is
Suppose I try to expand A node the I want only B & C,
If I expand B then I want B1 to B5
Use a XmlReader. XmlDocument by design has to load the whole Xml document into memory.
if you use java, you can implement a SAX Handler building your DOM and ignoring the children.
It's a badly worded question so I'm not entirely sure what you are trying to do but if you just want all the child nodes of the root (A) then use an XmlDocument with XPath like this:
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
XmlNodeList nodes = doc.SelectNodes("/A/*");
foreach(XmlNode node in nodes){
//DO STUFF
}
if i understand the question right, u need to get children of the node without getting their children. this can be done by xquery
(child::*)
so if u apply it in A node it will give B and C. if u apply it in B then it will give B1-B5.
I've got a XmlNodeList which I need to have it in a format that I can then re-use within a XSLT stylesheet by calling it from a C# extension method.
Can anyone help? I have read that it might have something to do with using a XPathNavigator but I'm still a bit stuck.
I had to solve this issue myself a couple of years ago. The only way I managed it was to create an XML fragment containing the nodes in the node list and then passing in the children of the fragment.
XsltArgumentList arguments = new XsltArgumentList();
XmlNodeList nodelist;
XmlDocument nodesFrament = new XmlDocument();
XmlNode root = nodesFragment.CreateElement("root");
foreach (XmlNode node in nodeList)
{
root.AppendChild(node);
}
nodesFragment.AppendChild(root);
arguments.AddParam("argumentname", string.Empty, nodesFragment.CreateNavigator().SelectChildren(XPathNodeType.All));
Then you need to make sure you have the corresponding argument in your XSLT, of course.
Note that you probably don't need the additional XmlDocument. You could just call CreateNavigator() on the root XmlNode instance and use your existing XmlDocument for creating the element (I wrote this code some time ago and I've learned more since then - but I know the code above works, I haven't tried any alternatives).
The note at the end was the most useful, I had infact transformed the XmlNodeList into a XmlDocument already so could just use the Navigator on there and create it as a XPathNodeIterator.
Thanks for you help!
Didn't succeed with the answer provided before.
Using AppendChild() to add previously selected nodes of XmlNodeList to a new document resulted in exception on trying to append nodes originating from a different document context. Several trials to fix this included adding my custom default namespace selected nodes in list are bound to. Finally I dropped the approach completely and switched the way I select nodes into XmlNodeList instances.
Instead of
myXmlNode.SelectNodes( xpath, nsmgr )
I'm using
myXmlNode.CreateNavigator().Select( xpath, nsmgr )
to get an XPathNodeIterator instead of XmlNodeList. The resulting XPathNodeIterator of second code is now properly added as parameter value to XsltArgumentsList.