I'm trying to parse an Xml file using QDomDocument.
I've got the root element. Now I need to find and extract specfic nodes
under the root element but only at the first level of hierarchy.
I tried to use:
QDomElement root = doc.documentElement();
QDomNodeList nodeList = root.elementsByTagName("apple");
But this returns me a nodeList which contains the nodes with tag Name "apple"
in all levels of hierarchy. But I need only a first level search.
Could someone please help me out.
Thanks
There's no method to do exactly what you want but it's easy to achieve by iterating over the children with something like:
QList<QDomElement> elements;
QDomElement child = root.firstChildElement("apple");
while(!child.isNull()) {
elements.append( child );
child = child.nextSiblingElement("apple");
}
Related
I have a custom Sitecore command that I would like to expand upon to determine if the current item has a parent item matching a certain template id.
When the command/button is clicked, I will have access to the current Item.
My initial attempt, since I had issues with escaping the FullPath for use in a query, was to loop through the parent item (and then that item's parent, etcetera) to determine if any matched the template.
However, there seems like there should be a better way to do this.
So given an item, what's the best way to find whether it has a parent item that is of a certain template?
SXA way
public static Item GetParentOfTemplate(this Item item, ID templateId)
{
if (item == null)
{
return null;
}
ItemRelationCacheValue itemRelationCacheValue = ParentOfTemplateCache.GetCacheForDatabase(item.Database.Name)?.Get(item, templateId);
if (itemRelationCacheValue != null)
{
return item.Database.GetItem(itemRelationCacheValue.OutputID);
}
Template template = TemplateManager.GetTemplate(templateId, item.Database);
if (template == null)
{
return null;
}
ID iD = item.ID;
while (item != null)
{
Template template2 = TemplateManager.GetTemplate(item);
if (template2 != null && template2.DescendsFromOrEquals(template.ID))
{
ItemRelationCacheValue value = new ItemRelationCacheValue(iD, item.Database.Name, templateId, item.ID);
ParentOfTemplateCache.GetCacheForDatabase(item.Database.Name)?.Set(value);
return item;
}
item = item.Parent;
}
return null;
}
There's not really a good way to do it. In a regular system you'd do it in SQL, but Sitecore has obfuscated their 'Nexus' code which I believe is where all of this data access/mapping logic happens thus I don't really know how that part of Sitecore works so it's a difficult to try to reverse engineer a query to do this efficiently.
What I use in my projects I use a recursive function like this.
I use a delegate to determine if the item is a match for what I'm looking for, and just recurse up the tree - dropping out to return null if it reaches the root node.
public delegate bool ItemSelectionCondition(Item sitecoreItem);
public static Item GetAncestor(Item sitecoreItem, ItemSelectionCondition selectionCondition)
{
Item parent = sitecoreItem.Parent;
if (selectionCondition(parent))
{
return parent;
}
else if (Sitecore.ItemIDs.RootID == parent.ID)
{
return null;
}
else
{
return GetAncestor(parent, selectionCondition);
}
}
So to work with this you'd need to define a delgate something like:
public static bool IsTemplateX(Item item)
{
return item.TemplateID == Constants.TemplateXId;
}
It's quite a simple solution that's flexible enough to work with any Ancestor or Parent type things that I've needed to do.
Be warned though it will take several seconds to run the first time if Sitecore hasn't cached all of the items it needs to look at, but subsequent times it will take a bearable amount of time.
EDIT: Since this answer has gotten a few downvotes I thought I'd explain why it's the best way to do this in Sitecore.
The reson why a recursive approach is better that iterative is two-fold. First, it's less code so it looks nicer - but if that's not enough the second reason is that if you're careful about how you've structured your code and are compiling your project you'll be able to take advantage of tail recursion.
The reason why using Item.Axes.Ancestors (Or Item.Axes.GetAncestors() in later versions of Sitecore) is bad is because it has five steps:
Allocate a List of Items
Iteratively add All Ancestors to that list
Reverse the order of the List
Convert the list to an array
Use Linq to filter the array
This means that you're doing twice as much allocation as if you were to just recurse to the top of the content tree, but you're also ruling out the possibility of exiting the recursion at the first relevant item - and avoiding unecessary calls to the database.
I do have to conceed that the comment about using a Lucene Index however is right - that's the way that is potentially the fastest in almost all scenarios just because it can reduce your time finding the item down to a single Sitecore Query - or no Sitecore Query if you index the data about that ancestor that you need.
I'm trying to make some kind of recursion. If you open P then you can open P again or do something else. And here is my problem:
I can't add same item twice.
while (*it) {
if ((*it)->text(0) == item->text(0)){
(*it)->setText(0,"Add_item");
(*it)->addChild(item);
}
}
Can I make a loop in QTree ?
You need to create another item. It seems you add for the same text the same item object over and over again as child. So making a copy of the item and adding that copy as child should work.
What is difference between getElementsByTagName() with tagName and with .//tagName ?
When we pass tagname in the getElementsByTagName(), in that what is the meaning when we add ".//" ?
What is the difference between
sSourceInputXml->
getElementsByTagName(_bstr_t(".//author"), &xml2);
and
sSourceInputXml->
getElementsByTagName(_bstr_t("author"), &xml2);
?
Both return me same number of elements.
Any help is appreciated.
// means location step descendant-or-self:node(), which retrieves the current node and all its descendants.
. means self::node() which gets the context node.
Default location step is child, which gets the child elements of the context node.
If you need more information, check here.
I want a code snippet to check if the first child node is a processing instruction or not?
For example :
<caml:Author>
<?PI-start data="processing instruction"?>
<caml:Leg> test data </caml:Leg>
</caml:Author>
In the above example the first child node of caml:Author tag is a processing instruction. How can I find if the first child node is a processing instruction ?
Remembering that you could also get comments or text nodes (the first child node of in your example is a text node), then if caml:Author is my current node, I would use the following to address the children:
test="(processing-instruction() | *)[1][self::processing-instruction()]"
The result is true if the first of the processing-instruction and element children is a processing-instruction.
I have a scenario where I would like to randomize the display of some items. Given a Parent item, how can I randomly select one of its child items?
Of course I could load ALL the children and apply some random index or whatnot... but that would be wildly inefficient.
I'm wondering if this is also inefficient:
Parent.Children[random(Parent.Children.Count)]?
At what point do the items get loaded when you access Parent.Children?
Item.Children is a lazy loaded property, and I would definitely not recommend using it exactly in the way you show here.
Before posting this, I did some digging through the API to see if there really isn't a way to get to the count of childitems without loading this property, but alas I couldn't really find any way that would seem "legitimate". Only the .HasChildren property seems to relate - and it seems to work by doing most (but not all) of what the .Children property does already.
However, given that it is lazy loaded, store the result of the property in a private field for maximum efficiency. I remember reading this in an official developer guideline at one point, I can dig out the exact reference if needed.
ChildList itemChildren = myItem.Parent.Children;
// Continue doing random() etc here, but using the itemChildren field.
Do you have the entire tree structure on hand? Then you could do some sort of random traversal. For example, you could select a random item from a binary tree like so (pseudo-code):
sub randomNode(node):
randomVal = random(0, 3); // random value between 0 and 3
if(randomVal == 0):
return randomNode(node.left) if node.left != null else return node;
elseif(randomVal == 1):
return randomNode(node.right) if node.right != null else return node;
else
return node;
For an n-ary tree, you could have something like this:
sub randomNode(node):
randomVal = random(0, 2)
if(randomVal == 0):
return randomNode(node.children[random(0, node.children.length)]) if node.children.length != 0 else return node;
elseif(randomVal == 1):
return node;
Doing parent.children[random(parent.children.count)] doesn't seem inefficient to me; it's what I've used in the algorithm above. As far as your last question, I guess it depends on how you've implemented your tree. If you've built up a tree structure on your own then you must have the whole tree structure on hand. If you're using a framework, then it depends on the implementation of that framework.