Can't display XML element name using Javascript - javascript

I have an HTML5 file with javascript to read in a local XML file.
One element in the XML structure is dynamic and contains inner xml, no value.
When trying to display this nodename on the webpage all I see is #text.
Example XML:
<Students>
<student id="1">
<Connor>
<age>20</age>
<gender>male</gender>
</Connor>
</student>
<student id="2">
<Fiona>
<age>25</age>
<gender>female</gender>
</Fiona>
</student>
</Students>
Javascript:
var x = xmlDoc.getElementsByTagName("student");
for(i = 0; i < x.length; i++)
{
var id = x[i].getAttribute("id");
var name = x[i].childNodes[0].nodeName; // produces '#text'
// var name = x[i].firstChild.nodeName; // produces '#text'
document.write("<p>name = " + x[i].childNodes[0].nodeName + "</p>"); // produces '#text'
var age = x[i].getElementsByTagName("age")[0].childNodes[0].nodeValue;
var gender = x[i].getElementsByTagName("gender")[0].childNodes[0].nodeValue;
var student= {id:id, name:name, age:age, gender:gender };
}
In my XML example I understand that the name of the student could be better stored but this is just an example based on a fixed XML structure I'm working with.
Furthermore: reading and displaying the XML file only works whilst running through the IDE. I would eventually like to be able to run the .html file and have the javascript code read the xml file (stored in the same location as the html file) and displays its data.
Edit: First part is solved. Still could use help on the "Furthermore" above.

Ahh this old chestnut, I had the same problem, try
var name = x[i].children[0].nodeName;
This should only get the first xml.
Basicallly the problem is in your list you have 0:text 1:XMLNode, 2:XMLnode ect.
And to get only xml stuff, you can use children rather then childNodes, very similar to HTML Elements
EDIT this example doesn't work
The actual answer:
You need to check the typeof child by using typof when looping throught

I have found a suitable answer for the first part of my question which appears to be a duplicate of:
Javascript/XML - Getting the node name
I've only seen this now in the related questions to my own. It wasn't shown to me when searching or when writing my question. So props to #T.J. Crowder
my solution is:
var nameNode = x[i].firstChild;
while(nameNode.nodeType != 1)
{
nameNode = nameNode .nextSibling;
}
var name = nameNode;

Related

How to remove items from a NodeList based on their type?

Context: I'm trying to parse an XML file for certain information. For some reason, when I read in the XML, it is reading in the different XML sections 2 times each, once as 'text' and once as the actual XML tag (in my case, 'Transaction').console log of Nodelist shown in this picture
Here is my code for reading in the XML and my beginning attempt to remove the nodes:
//At this point I have read in the XML file as a big string and passed it to this function
function parseXML(content) {
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(content, 'text/xml');
//access to XML nodes and get node values
var catalog = xmlDoc.getElementsByTagName('Transactions')[0];
var cNodes = catalog.childNodes;
console.log(cNodes); //this console.log shows the data that you see in the picture above
//Want to loop through child nodes and remove all of type 'text' and just keep the ones of type 'transaction'
for (var x=0; x < catalog.childNodes.length; x++) {
if (catalog.childNodes[x].__proto__ == "Text") {
//want to remove all nodes of type 'text' here
}
}
What I want to do is get rid of the nodes of type 'text' and just keep the 'transaction' nodes. Not quite sure how to do this as I have never done this before. Let me know if you need any more information for my question to make sense. Any help is appreciated!

InDesign Scripting: Deleting elements from the structure panel

I've imported some XML files inside InDesign (you can see the structure in the picture below) and I've also created a script to get some statistics concerning this hierarchy.
For example, to count the "free" elements:
var items = app.activeDocument.xmlElements.everyItem();
var items1 = items.xmlElements.itemByName("cars");
var cars = items1.xmlElements.everyItem();
var c_free = cars.xmlElements.itemByName("free");
var cars_free = c_free.xmlElements.count().length;
I also have apartments in my structure that's why I'm using itemByName.
The code above returns the correct number of free cars in my structure.
What I'm trying to do - without any luck so far - is to target those free items (inside cars) and either delete all of them or a specific number.
My last attempt was using:
var del1 = myInputGroup2.add ("button", undefined, "Delete All");
del1.onClick = function () {
cars.xmlElements.everyItem().remove();
}
inside a dialog I've created.
Any suggestions will be appreciated cause I'm really stuck here.
I would probably use XPath for this. You can use evaluateXPathExpression to create an array of the elements you want to target. Assuming your root element is cars and it contains elements called cars1, and you want to delete all free elements within a cars1 element, you could do something like:
var myDoc = app.activeDocument;
//xmlElements[0] is your root element, in this case "cars". The xPath expression is evaluated from cars.
//evaluateXPathExpression returns an array of all of the free elements that are children of cars.
var myFrees = myDoc.xmlElements[0].evaluateXPathExpression("cars1/free");
for (var i = myFrees.length - 1; i>=0; i--){
myFrees[i].remove();
}
Tweaking this would require some knowledge of xPath, but it's not terribly hard to learn the basics and it does seem like the simplest approach.
I think your main problem was that XMLElements hasn't a itemByName method. You can only reference XMLElements through their indeces or ids.
Secondly you assume that you got xmlElements from XPath expression but it's likely that you got nothing as your xpath seems uncorrect.
var myFrees = myDoc.xmlElements[0].evaluateXPathExpression("./cars1/free");
var n = myFrees.length;
if ( !n ) {
alert("Aucun élément trouvé");
}
else {
while (n--) myFrees[n].remove();
}
You need to start your expression by setting the origin of your xpath. Here a dot "./" is used to tell you want to look for cars1/free xml elements at the "root" of the xmlelement. Using "//" on the contrary would have returned any cars/free items unregardingly of their locations.

Getting json sibling data

I currently have a json object, that I loop through and output a list of links.
See fiddle:
http://jsfiddle.net/jasonday/hzZ8j/
each link is given an id based upon the storeID in the json.
What I want to do, is when a link is clicked it finds the id in the json, and then writes the sibling element "otherData" to #otherDataDiv
I've worked with traversing xml, but I'm not sure how to accomplish this with json.
Any help would be appreciated. thanks.
You just have to loop over, like this:
var target = "store17",
foundStore = {};
for(var k1 in object.state){ var state = object.state[k1];
for(var k2 in state.store){ var store = state[k2];
if (store.storeid == target){
foundStore = store;
break;
}
}
}
However, if you were using jQuery templates then you could just look for 'tmplItem' in the data array on the element.
Additionally, if you weren't building the HTML manually for this, I would suggest using jQuery data here for this project. It would solve your problem immensely.
to store: $(selector).data('unique name here',data);
to retrieve: var usefulname = $(selector).data('unique name here');
and then in your onclick for each link you could:
var otherData = $(this).data('unique name here').otherData;

Parsing an HTML like String in Javascript or JQuery

So I have a string like this
string = "<user>username 1<notes>Notes of User 1</notes></user> <user>username 2<notes>Notes of User 2</notes></user>"
How could I parse the string in Javascript or JQuery to pull out the "Notes" of either user 1 or user 2.
So I'll have a variable like this:
variable = user;
printout notes of user.
You mean an XML like string, not a HTML like string. jQuery has a lovely XML parser for that http://api.jquery.com/jQuery.parseXML/
to identify the notes of user1 or user2 you need to change your xml a bit
string = "<user>username 1<notes id='user1'>Notes of User 1</notes></user> <user>username 2<notes>Notes of User 2</notes></user>"
notice that i added id=user1
alert($(string).find("notes[id='user1']").text());
here is the fiddle http://jsfiddle.net/Qa5sP/
EDIT after the -1 :(
No, jQuery selectors do not parse XML.
This may appear to work at times, but it's invalid and browser-dependent.
So, here is the parseXML way:
xmlDoc = $.parseXML(string),
$xml = $(xmlDoc),
$title = $xml.find("notes[id='user1']").text();
alert($title);
Live demo.
Here's a JSFiddle. It's simple to do using jQuery if you are using HTML-parsible XML (as seen above).
string = "<user>username 1<notes>Notes of User 1</notes></user> <user>username 2<notes>Notes of User 2</notes></user>";
var node = $("<div>" + string + "</div>");
alert(node.find('notes').text());
node.attachTo(document.body); //append to dom?
I would rather go with this approach.
var xml = "<user>username 1<notes>Notes of User 1</notes></user> <user>username 2<notes>Notes of User 2</notes></user>";
function FindNotesByUserName(uName) {
var node = $('<div/>').html(xml);
return node.find(":contains('" + uName + "')").closest("user").find("notes").text();
}
var desiredNotes = FindNotesByUserName("username 2");
N.B: This is a minor alteration of what ghayes did. Just to meet OP requirement.

Html collection has a .length but undefined .item(*)

I have a function that calls to an xml page, picks out elements by the tag names, and I'm trying to call back a specific one. code so far is:
var xmlDoc = loadXMLDoc("test.xml");
var x = xmlDoc.getElementsByTagName("tagname");
var PittWins = x.item(2);
This will come back [object element]
var xmlDoc = loadXMLDoc("test.xml");
var x = xmlDoc.getElementsByTagName("tagname");
var PittWins = x[2].data;
The above code gives me undefined.
var xmlDoc = loadXMLDoc("nhl.xml");
var x = xmlDoc.getElementsByTagName("tagname");
var PittWins = x.length;
when entered above, i get a result which is correct.
I am trying to understand why it's giving me a length and not a specific node..
What about var PittWins = x[2];?
Re: OP edit
You're saying that x.item(2) and x.length return what you expect, but x[2].data does not? Why do you expect the element to have a data property? Are you trying to write the bracketed version of x.item(2)?
x.item(2) is equivalent to x[2].
x.item(2).data is equivalent to x[2].data.
What are you trying to do? Also, you've used different XML file names and tag names across your different examples. Is this intentional?
Edit #2
To retrieve the text content of an element, use Node.textContent or Node.nodeValue. Your code might look like this, then:
var PittWins = x[2].textContent;

Categories