Accessing a node-set in a JavaScript XPath query - javascript

I have a real simple question that I can't seem to find an answer to.
I want to compress two XPath statements (that are getting attribute values). I learned about the | operator, hearing how it returns node sets.
var getdata = xmldoc.evaluate
(
'/foo/bar[#world=\''+hello+'\']/child::*/attribute::name
|/foo/bar[#world=\''hello+'\']/child::*/attribute::id',
xmldoc, null, XPathResult.ANY_TYPE, null
);
To anyone wondering, no I do not format my evaluation strings that way ... though, I sort of like it now that I typed it out. Anyways, this is how I tested it out.
alert(getItemData.iterateNext().childNodes[0].nodeValue);
That works! But it only returns the first one. While writing this, I just tried .length and made a break through ... it's only counting one item. Was I deceived about the concept of |? How can I get a set and then go through them?
XML document, as requested.
<?xml version="1.0" encoding="ISO-8859-1"?>
<foo>
<bar world="hello" id="1">
<subbar name="item1" id="2">
</subbar>
</bar>
<bar world="bye" id="3">
<subbar name="item2" id="4">
</subbar>
</bar>
</foo>
Edit: I am currently using a function that grabs the element rather than the attribute, but I would really like to know the other way. Unless what I am doing is the best way.

If JQuery is an option, it might be worth your while to check out their XML traversal library. A quick search pulled up an article here. I wrote up a very rough example of what the logic may look like after you import the xml document, which is explained in the link.
var hello = "foo";
$('bar[world=' + hello + '] > subbar').each(function () {
// You'd want to save these values somewhere else, obviously.
$(this).getAttribute(name);
$(this).getAttribute(id);
});

The key here is the XPathResult type you use.
I have implemented a working sample for the same.
Please refer the code at http://jsbin.com/eneso3/5/edit
Basically you have to use Iterator as result type sot hat we can iterate through them to get the text. Refer Xpath reference mentioned on the working code sample page.

Well your usage of the "pipe" is correct (http://www.tizag.com/xmlTutorial/xpathbar.php) so the only code that I can see might be off is a missing + in the second xpath command, but that might be pseudo code, so I would only count this as a half answer. As for the best practice, in my opinion I would grab the subbar element then grab it's attributes out where you need them an optimization like the one you've suggested obfuscates what data is being referenced. Seems too much of a mico-optimization, but this is just an opinion. Maybe you have a long list of attributes and you really are saving parsing time.

Related

Format integer thousands separator throughout the document

After months of web-development, I find myself completely helpless trying to find a good solution for a simple problem of formatting all the numbers throughout the DOM as I wish. Specifically, I have a js function my_int_formatter(), that I want to apply to all integers after the doc has been loaded. Best descriped by example - I want to do something like
<td>my_int_formatter({{django_variable}})</td>
I know the code above won't work, because I have to include 'script' tag, but first, I don't like the messy code, and second, javascript won't recognize python variable
I tried the following way:
HTML
<td class = 'my_integer'>{{django_variable}}</td>
JS
$(document).ready(function(){
// ....
content = $('.my_integer').html();
$('.my_integer').html(my_int_formatter(content));
...but as expected, I got wrong results because the js code applied the same html() content of the first .my_integer element in the DOM chain to all the others. Any ideas how to do this the short and correct way ?
If I understand correctly, your problem isn't with the formatting but actualy applying the formatting to each of your dom elements.
Try using jquerys .each() function and using $(this).html() to actualy grab the content.
$('.my_integer').each(function(){
content = $(this).html();
$(this).html(content+"formatted");
});
here's a quick fiddle :
https://jsfiddle.net/57rdq2a0/2/
If I understand you correctly, you want to use builtin django.contrib.humanize application: https://docs.djangoproject.com/en/1.9/ref/contrib/humanize/
You can format integers using some predefined filters, for example intcomma:
4500 becomes 4,500.
45000 becomes 45,000.
450000 becomes 450,000.
4500000 becomes 4,500,000.
Usage in your case would be like
{% load humanize %}
<td>{{django_variable|intcomma}}</td>
Also don't forget to include the app in INSTALLED_APPS
Also this question might be useful
If you want to apply filter to all variables of some kind, I suggest you to use Middleware to fiddle with response before rendering.

E4x delete node where something in the node equals something

So I have some xml....
<parentnode>
<childnode>
<babynode id="1">
<parameter>goes here</parameter>
<babynode />
<childnode />
<parentnode />
<parentnode>
<childnode>
<babynode id="2">
<parameter>goes here</parameter>
<babynode />
<childnode />
<parentnode />
...and, using e4x, I want to delete to delete a parent node where a babynode id is equal to something. For example where baby node id is 2, I want to delete the whole node starting from <parentnode>.
I know I can do var xml = the xml and then do delete xml.parentnode but I am not sure how I specify which parentnode to delete.
I am sure this is probably simple, and I am probably being silly, but could anyone point me in the right direction please?
Thanks
First off, if your environment is the browser or even a Firefox extension, I'd advise against continuing with E4X as they have deprecated it.
That being said, here is what I could find in testing around about what works (very little) and what does not, in attempting to do what you are trying to do.
As useful as it would be, and as well as it seems it would fit into the filter/accessor syntax, deleting a parent (or grand-parent in your case) does not seem to work (at least when I try with Mozilla's E4X engine--btw, as I recall, the function:: used below might only be supported in Spidermonkey).
var a = <a>
<b>
<c/>
</b>
</a>;
delete a.b.c.parent(); // Removing parent() will delete <c/>
alert(a); // <b/> is not deleted
Thus naturally, in taking your example:
var xml = <><parentnode>
<childnode>
<babynode id="1">
<parameter>goes here</parameter>
</babynode>
</childnode>
</parentnode>
<parentnode>
<childnode>
<babynode id="2">
<parameter>goes here</parameter>
</babynode>
</childnode>
</parentnode></>;
...while this (using the .. descendant selector):
alert(xml..*.(function::attribute('id') == "2")[0].parent().parent()); // I'm also not sure why the formatting of the attribute cannot be obtained by `xml..*.(#id == "2")` without giving an error since id is not a reserved word, but anyways...
...does get the <parentnode> you want, deleting it like in the following does not work:
delete xml..*.(function::attribute('id') == "2")[0].parent().parent();
...even while this:
delete xml..*.(function::attribute('id') == "2")[0];
...will at least delete the <babynode> part you want to delete.
Theoretically, I would think that the following (i.e., without the * mark which selects the filtered elements of descendants instead of just filtering the ancestor) should work (or at least it would be nice if it did!):
delete xml..(function::attribute('id') == "2")[0];
...yet it does not.
Even accessing an element in this manner (of not grabbing a descedant) does not seem to work:
alert(xml..(function::attribute('id') == "2")[0]);
And even if we avoid using an XMLList (<></> being the short-hand syntax used above if you were not familiar with it) and wrap the XML in some named element, say <container>, deleting or accessing still does not work:
delete xml.container..(function::attribute('id') == "2")[0];
You could take a look at http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-357.pdf to see if your reading should allow this, but in any case it does not work, at least as I've tried it.
So, as far as I can see, the only solution would be to iterate through the elements and track where you are manually rather than using filters.

Javascript xPath [#StoreName]?

I'm doing some research for a project that I have going on the uses the document.createTreeWalker and I'm looking at a script that uses quite a few xpath's, but I'm curious as to where these come from. Some are obvious and I have been able to find answers to online, such as [#AttributeName] and [#TagName], but what is [#StoreName], [#AttributeValue1], [#AttributeValue2]...these I have not been able to look up online.
Particularly, I'm looking at these lines and not understanding:
thisURL = window.document.location.href.toString();
if(thisURL.search("[#StoreName]") != -1) { //do something }
Perhaps I'm misunderstanding your question, but there's nothing functionally or syntactically different between [#AttributeName] and [#StoreName]. They're both predicates that are looking for elements with particular attributes. The first one is looking for AttributeName attributes, while the second is looking for StoreName attributes.
That said, the code you're showing isn't actually doing any XPath work. It's just looking at whether the URL contains the character sequence [#StoreName] using JavaScript's string search function, and doing something if it does.

XPath selector for JQuery

I'm looking for a jQuery plugin or anything that will allow me to easily select elements through xpath after parsing an XML using $.parseXML.
There's no way to use CSS selectors, as that's a javascript port for a .NET program that already uses XPath selectors.
I've seen a lot of questions asked on the matter, but couldn't see any viable answers, while it looks quite a basic need, and it came as a surprise when I learned it's not supported.
Thanks!
EDIT:
The problem is NOT parsing the XML, that I know how to do.
The problem is running XPath queries on the parsed XML.
Right now the required support is for Android and iOS native browsers(that are both webkit-based), but Windows Phone might need support soon too.
You can also do:
$('person', myXML).each(function(){
//blah
});
The selector takes two parameters. The second parameter is the context in which to find the selector which defaults to document
You can get xml values like this:
$(myXML).find('person').each(function(i, val) {
// i is the counter of this element
var age = $(val).attr('age'); // this is an attribute of the person node
var firstName = $(val).find('firstname').text();
var lastName = $(val).find('lastname').text();
}
This will work with:
...
<person age="3">
<firstname>Babe</firstname>
<lastname>Ruth</lastname>
</person>
<person age="44">
<firstname>Hank</firstname>
<lastname>AAron</lastname>
</person>
...
See here
Well, I've found no good answer.
As a viable alternative I've found this nice library from GoogleCode: http://goog-ajaxslt.sourceforge.net/
There's a cross-browser XPath implementation there that can be used independently from the whole framework, and work's great.

e4x newb woes - attribute trace

Sorry if I'm doing anything really dumb, but could anybody see anything immediately wrong with the following?
var layout = new XML()
layout=
<layout color="red">
</layout>
function init()
{
post(layout.#color);
}
it returns what I assume to be a ram address rather than the value.
In the event that the software in question wants an object of type string, what is the best way to enforce that? I doubt thats the cas, but am willing to try
A string cast should work fine, e.g.:
trace(String(layout.#color));
Note that in your example there's no need to assign a new XML object to layout, since you overwrite it with the next assignment one line later.
This article is highly useful if you're just getting started with E4X.

Categories

Resources