Get Collection after traversing in Umbraco - c#

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.

Related

Navigate between XML Elements with Same Attribute

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'"

Tree filtering performance

Currently I have a structure that looks like:
Name,Type, RefName, RefType
The goal is that the user selects an element and a direction and then get a treestructure in a webpage (JSON data) that displays all elements matching his criteria. As you can imagine, going up is not hard. The tree structure gets narrower and thus performance is no issue. While going down more and more nodes get added and at a certain point it gets slow. At this moment the nodes are added to a HashSet and I go recursively trough them. My program structure for going down is:
private void BuildChildNodes(ElementRefItem element, int goalDepth, int currentDepth =0)
{
if (goalDepth <= currentDepth)
{
return;
}
currentDepth++;
var elements = refElementRepository.All().Where(x => x.ElementName == element.Name);
foreach (var refElement in elements)
{
var node = CreateNode(refElement.ElementRefName, refElement.ElementRefType);
BuildChildNodes(node, goalDepth, currentDepth);
element.ChildNodes.Add(node);
}
}
I am looking for tips to optimize this part of the code. Are there other ways of doing this faster?
(Actual data structure is a bit more complex, but for clarity it is easier to show this version)
Instead of performing a query every time I retrieve the data once (all data is refreshed once a day) and I build two HashSets; one for parent-child relations and one for child-parent relations. This makes it possible to find an element in the HashTable (witch is very fast) and therefor retrieving the whole tree part. In meta code it looks like this:
- Create new cache (bottom up, top down)
- Foreach CachedObject
- Check if items exist (both parent and child)
: yes -> select node
: no -> create node and insert it in the new cache
- add child to parent node
This gives a hashset of Parent objects. Now you can select a parent object and automagically you get your whole tree section.

how to replace TreeView's selected node with newly created node

I have a populated treeView with Node I created, there are several node classes, all inherit from treeNode.
When i edit a node (using a GUI dialog), it may change to different class, so I'm creating a new node in that process, and trying to replace the selected node with my new node, but that doesn't work, the node stays the old one, cant figure out what i'm doing wrong.
Code:
TreeNodeMission mission = (TreeNodeMission)treeView.SelectedNode;
TreeNodeMission newMission = ChangeMissionDialog(mission);
treeView.SelectedNode = newMission; // doesn't work
Also tried removing and adding it, also doesn't work
index = treeView.Nodes.IndexOf(treeView.SelectedNode); // index returns -1
treeView.Nodes.Remove(treeView.SelectedNode);
treeView.Nodes.Insert(index, newMission);
What am i doing wrong?
Update:
treeView.SelectedNode is not null, its a valid node i selected.
Solved it, found the bug.
I found a way to replace the node, by removing and re-adding it.
I guess i thought asking for index will give me general index in the tree, but it gives index to the parent only, so using the parent node, i can replace it:
int index = treeView.SelectedNode.Index;
treeView.SelectedNode.Parent.Nodes.RemoveAt(index);
treeView.SelectedNode.Parent.Nodes.Insert(index, mission);
treeView.SelectedNode = mission;
Thanks

Question mark inside XML file without encoding produces errors while trying to load it

I am trying to get all the elements in a selected "Xpath location" and add them to a comboBox/ drop down list.
I tried to select all these elements by using the Xpath query : /#* with the Select method from the XpathNodeIterator.
The problem is that it return an iterator which does not move forward, in fact, it says it has no childs and its not allowing me to convert the iterator neither to an xmlElement or node so that I could at least search inside them.
This is the code :
while (anIterator.MoveNext())
{
//im trying to select all nodes of selected path which and return them to an iterator
secondIterator = anIterator.Current.Select("/#*");
while (secondIterator.MoveNext())
{
aNode = new Nodes();
aNode.Name = anIterator.Current.MoveToFirstChild().ToString();
nodeList.Add(aNode);
}
nodeList.Add(aNode);
}
Any solution to get all the elements in the current node ?
This is definitely harder to answer without the XML file you're working with, and without you telling us what you're hoping to see, and what you're currently seeing.
Here are some observations:
The '#' character in your XPath suggests you're trying to get all of the attributes of the current Node. The '/' tells Path to start at the root of the DOM.
If you're trying to get all the elements under the current node, you might want to change to "./*"
The issue is the #, which indicates that you want to select the child attributes, not child elements. (See http://www.w3.org/TR/xpath/#path-abbrev).
Try anIterator.Current.Select("*") to get the child elements. If you want all descendant elements (not just immediate children), try anIterator.Current.Select(".//*")

Reading an XML File and Selecting Nodes in .NET

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,

Categories

Resources