I have what should be an extremely simple xml question, which has me completely lost.
I have the following XML file:
<items>
<item percentFinished="0.0">
<details>
<name>Objective 1</name>
<description>Test objective</description>
</details>
</item>
<item percentFinished="0.0">
<details>
<name>Objective 2</name>
<description>Another objective</description>
</details>
<subitems>
<item percentFinished="0.0">
<details>
<name>Sub Objective 1</name>
<description>A Sub Objective</description>
</details>
</item>
</subitems>
</item>
</items>
The javascript file is eventually going to be creating dynamic html from the xml file, but for now I am just trying to get the parsing down properly. Here is my current javascript file:
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
} else {// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("GET","defaultData.xml",false);
xmlhttp.send();
xmlDoc=xmlhttp.responseXML;
// HTML Div
var outer = document.createElement('div');
var div = document.createElement('div');
// Gets the item list from the XML
var itemList = selectValue(xmlDoc,"items/item");
var item = itemList.iterateNext();
while (item!=null) {
parseItemNode(item,div);
item = itemList.iterateNext();
}
outer.appendChild(div);
document.write(outer.innerHTML);
function parseItemNode(itemNode, parentNode) {
var details = selectValue(itemNode,"item/details").iterateNext();
var name = selectValue(details,"name").stringValue;
}
function selectValue(context,xpath) {
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
var nsResolver = document.createNSResolver( context.ownerDocument == null ? context.documentElement : context.ownerDocument.documentElement );
return document.evaluate(xpath, context, nsResolver, XPathResult.ANY_TYPE,null);
} else {
return context.selectNodes(xpath);
}
}
So the issue I am having is: the details variable in the parseItemNode() function is null.
I had a look at the selectValue(itemNode,"item/details") call in the debugger, and the result is this:
XPathResult {invalidIteratorState: false, resultType: 4, iterateNext: function, snapshotItem: function, ANY_TYPE: 0…}
booleanValue: [Exception: TypeError: Failed to read the 'booleanValue' property from 'XPathResult': The result type is not a boolean.]
invalidIteratorState: false
numberValue: [Exception: TypeError: Failed to read the 'numberValue' property from 'XPathResult': The result type is not a number.]
resultType: 4
singleNodeValue: [Exception: TypeError: Failed to read the 'singleNodeValue' property from 'XPathResult': The result type is not a single node.]
snapshotLength: [Exception: TypeError: Failed to read the 'snapshotLength' property from 'XPathResult': The result type is not a snapshot.]
stringValue: [Exception: TypeError: Failed to read the 'stringValue' property from 'XPathResult': The result type is not a string.]
__proto__: XPathResult
At this point, I have no idea what is going on or how to fix it, and I haven't been able to dig up anything on Google. Can someone explain to me what is happening, and how I should make it work correctly?
The details variable in the parseItemNode() function is null because the itemNode variable is the <item/> node itself.
Therefore, applying Xpath item/details on this <item/> will return the <details/> that are child of <item/> that are child of <item/>, hence, no node.
Switch the XPath expression to 'details' only since you're applying it on <item/> node.
Btw, XSLT is designed to build (X)HTML upon any XML source.
Related
I'm using jQuery to extract SOAP XML data from an AJAX response using the following code inside the success callback. I'm using the example from https://api.jquery.com/jQuery.parseXML/ for reference. The reason I'm not using the $.parseXML() function is because data is already a parsed response and attempting to parse it again renders a null response.
My success callback (curShipment is a variable for storing the required info in a JSON format, you can ignore it):
success: function(data) {
var $xml = $( data );
if ($xml.find("error").text() != "") {
resetUI();
alertMessage($xml.find("error").text(), "danger");
} else {
curShipment.labelId = $xml.find("id").first().text();
curShipment.loo_wb = $xml.find('value').first().text();
curShipment.senderName = $xml.find('pickup_name').text();
curShipment.consigneeName = $xml.find('delivery_name').text();
saveShipment();
}
This code was originally working in Chrome last week and once Chrome updated to v60 it no longer does. I would blame this on a Chrome bug except for the fact it never worked in Firefox or Internet Explorer. So, obviously, there's an issue with my code that Chrome was somehow working around in the previous version. Any advice would be greatly appreciated - I have very little jQuery experience.
Here's console.log(data) (sorry it's so long - I actually removed half of it):
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:processShipmentResponse xmlns:ns="http://ws.business.uss.transforce.ca">
<ns:return xsi:type="ax25:ProcessShipmentRs" xmlns:ax27="http://dto.uss.transforce.ca/xsd" xmlns:ax25="http://ws.business.uss.transforce.ca/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ax25:error xsi:nil="true"/>
<ax25:processShipmentResult xsi:type="ax27:ProcessShipmentResult">
<ax27:shipment xsi:type="ax27:Shipment">
<ax27:billed_weight>21.0</ax27:billed_weight>
<ax27:billed_weight_unit>L</ax27:billed_weight_unit>
<ax27:collect_shipper_num/>
<ax27:consolidation_type/>
<ax27:courier>L</ax27:courier>
<ax27:delivery_address_id/>
<ax27:delivery_address_line_1>123 MAIN ST</ax27:delivery_address_line_1>
<ax27:delivery_address_line_2>STE 200</ax27:delivery_address_line_2>
<ax27:delivery_address_line_3/>
<ax27:delivery_city>MISSISSAUGA</ax27:delivery_city>
<ax27:delivery_country>CA</ax27:delivery_country>
<ax27:delivery_email>DELIVERIES#LOOMIS-EXPRESS.COM</ax27:delivery_email>
<ax27:delivery_extension>1234</ax27:delivery_extension>
<ax27:delivery_name>COMPANY NAME HERE</ax27:delivery_name>
<ax27:delivery_phone>9055551212</ax27:delivery_phone>
<ax27:delivery_postal_code>L5R3R3</ax27:delivery_postal_code>
<ax27:delivery_province>ON</ax27:delivery_province>
<ax27:delivery_residential>false</ax27:delivery_residential>
<ax27:dimension_unit>I</ax27:dimension_unit>
<ax27:estimated_delivery_date xsi:nil="true"/>
<ax27:freight_charge>0.00</ax27:freight_charge>
<ax27:fuel_surcharge>1.20</ax27:fuel_surcharge>
<ax27:id>10000734</ax27:id>
<ax27:inserted_on>2017-04-07T11:03:30.508-04:00</ax27:inserted_on>
<ax27:manifest_num xsi:nil="true"/>
<ax27:packages xsi:type="ax27:Package">
<ax27:billed_weight>20.5</ax27:billed_weight>
<ax27:dim_weight>0.0</ax27:dim_weight>
<ax27:dim_weight_flag>false</ax27:dim_weight_flag>
<ax27:id>10005262</ax27:id>
<ax27:inserted_on>2017-04-07T11:03:30.508-04:00</ax27:inserted_on>
<ax27:min_weight_flag>false</ax27:min_weight_flag>
<ax27:package_info_str xsi:type="ax27:PackageInfoStr">
<ax27:id>10002317</ax27:id>
<ax27:inserted_on>2017-04-07T11:03:31.241-04:00</ax27:inserted_on>
<ax27:name>PIN</ax27:name>
<ax27:updated_on>2017-04-07T11:03:31.241-04:00</ax27:updated_on>
<ax27:value>LSHA00007014</ax27:value>
</ax27:package_info_str>
<ax27:package_num>0</ax27:package_num>
<ax27:package_reference>0</ax27:package_reference>
<ax27:reported_weight>20.5</ax27:reported_weight>
<ax27:updated_on>2017-04-07T11:03:31.241-04:00</ax27:updated_on>
</ax27:packages>
<ax27:pickup_address_line_1>5555 DIXIE RD</ax27:pickup_address_line_1>
<ax27:pickup_address_line_2>BUILDING 2</ax27:pickup_address_line_2>
<ax27:pickup_address_line_3>STE 500</ax27:pickup_address_line_3>
<ax27:pickup_city>MISSISSAUGA</ax27:pickup_city>
<ax27:pickup_email>SHIPPING#LOOMIS-EXPRESS.COM</ax27:pickup_email>
<ax27:pickup_extension>6162</ax27:pickup_extension>
<ax27:pickup_name>LOOMIS EXPRESS</ax27:pickup_name>
<ax27:pickup_phone>9054528769</ax27:pickup_phone>
<ax27:pickup_postal_code>L4W1E6</ax27:pickup_postal_code>
<ax27:pickup_province>ON</ax27:pickup_province>
<ax27:proforma xsi:nil="true"/>
<ax27:reported_weight_unit>L</ax27:reported_weight_unit>
<ax27:service_type>DD</ax27:service_type>
<ax27:shipment_info_str xsi:type="ax27:ShipmentInfoStr">
<ax27:id>10005201</ax27:id>
<ax27:inserted_on>2017-04-07T11:03:31.194-04:00</ax27:inserted_on>
<ax27:name>CODE</ax27:name>
<ax27:updated_on>2017-04-07T11:03:31.241-04:00</ax27:updated_on>
<ax27:value>AA</ax27:value>
</ax27:shipment_info_str>
<ax27:shipment_info_str xsi:type="ax27:ShipmentInfoStr">
<ax27:id>10005202</ax27:id>
<ax27:inserted_on>2017-04-07T11:03:31.194-04:00</ax27:inserted_on>
<ax27:name>SERVICE_LABEL</ax27:name>
<ax27:updated_on>2017-04-07T11:03:31.241-04:00</ax27:updated_on>
<ax27:value>GRD</ax27:value>
</ax27:shipment_info_str>
<ax27:shipment_info_str xsi:type="ax27:ShipmentInfoStr">
<ax27:id>10005203</ax27:id>
<ax27:inserted_on>2017-04-07T11:03:31.194-04:00</ax27:inserted_on>
<ax27:name>BRANCH_CITY</ax27:name>
<ax27:updated_on>2017-04-07T11:03:31.241-04:00</ax27:updated_on>
<ax27:value>BRAMPTON</ax27:value>
</ax27:shipment_info_str>
<ax27:shipment_info_str xsi:type="ax27:ShipmentInfoStr">
<ax27:id>10005204</ax27:id>
<ax27:inserted_on>2017-04-07T11:03:31.241-04:00</ax27:inserted_on>
<ax27:name>SIN</ax27:name>
<ax27:updated_on>2017-04-07T11:03:31.241-04:00</ax27:updated_on>
<ax27:value>LSHA00007014</ax27:value>
</ax27:shipment_info_str>
<ax27:shipment_status>R</ax27:shipment_status>
<ax27:shipper_num>HB4499</ax27:shipper_num>
<ax27:shipping_date>20170407</ax27:shipping_date>
<ax27:tax_charge_1>1.26</ax27:tax_charge_1>
<ax27:tax_charge_2>0.00</ax27:tax_charge_2>
<ax27:tax_code_1>GST</ax27:tax_code_1>
<ax27:tax_code_2/>
<ax27:transit_time>1</ax27:transit_time>
<ax27:transit_time_guaranteed>false</ax27:transit_time_guaranteed>
<ax27:updated_on>2017-04-07T11:03:31.241-04:00</ax27:updated_on>
<ax27:user_id>ADMIN#USS.COM</ax27:user_id>
<ax27:voided>false</ax27:voided>
<ax27:zone>1</ax27:zone>
</ax27:shipment>
</ax25:processShipmentResult>
</ns:return>
</ns:processShipmentResponse>
</soapenv:Body>
</soapenv:Envelope>
if I do console.log($xml) and expand the object, this is what I see:
Screenshot
I expanded the documentElement which is the soap envelope and under that object, you can see the rest of the XML within the innerHTML element.
Thanks!
Adding the namespace with \\: appended fixed the issue. The following callback works on both Chrome, Firefox & IE. However, it does not work on Edge. Edge only works when no namespace is specified.
success: function(data) {
var $xml = $( data );
if ($xml.find("ax25\\:error").text() != "") {
resetUI();
alertMessage($xml.find("ax25\\:error").text(), "danger");
} else {
curShipment.labelId = $xml.find("ax27\\:id").first().text();
curShipment.loo_wb = $xml.find('ax27\\:value').first().text();
curShipment.senderName = $xml.find('ax27\\:pickup_name').text();
curShipment.consigneeName = $xml.find('ax27\\:delivery_name').text();
saveShipment();
}
The below code gives different output in chrome and IE
<script src="\xyz\jquery-1.11.1.min.js"></script>
<script>
var xml= $("<root/>");
var field=$("<Field/>");
$(field).attr('Name','DateOpened');
$(field).attr('DisplayName','DateOpened');
$(field).attr('Type','DateTime');
$(field).attr('Format','DateOnly');
$(field).attr('Required','FALSE');
var schema= $(field);
xml= $(xml).append(schema);
string= $(xml).prop('outerHTML');
xmlDoc=$.parseXML(string);
</script>
i have also used:
if (window.DOMParser)
{
parser=new DOMParser();
xmlDoc=parser.parseFromString(string,"text/xml");
}
else // Internet Explorer
{
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.loadXML(string);
}
In both the cases output for chrome is:
<root><field name="DateOpened" displayname="DateOpened" type="DateTime" format="DateOnly" required="required"/></root>
and i can access the name attribute like $(xmlDoc).find(field).attr('name');// DateOpened
but in IE 8 i am getting the output like
<root><Field name="DateOpened" displayname="DateOpened" type="DateTime" format="DateOnly" required="required"></Field></root>
and $(xmlDoc).find(field).attr('name')// undefined
and in IE 9 i am getting the output like:
<root><field Name="DateOpened" DisplayName="DateOpened" Type="DateTime" Format="DateOnly" Required="required"/></root>
and $(xmlDoc).find(field).attr('name')//undefined
is it possible to get the output in same format across browsers? so that i can get the field and attributes in consistent way across browsers.
I want to get the stats from my XML when someone is asking for a particular name, but my javascript doesn't work like I want.>br>
Here's my XML :
<player>
<forward><name>Joe</name><stats>45</stats></forward>
<forward><name>Jack</name><stats>42</stats></forward>
<forward><name>Peter</name><stats>34</stats></forward>
<forward><name>Steve</name><stats>21</stats></forward>
<goalie><name>Pat</name><stats>2.34</stats></goalie>
</player>
Here's my HTML (ajax) :
<html>
<head>
<script language="JavaScript">
function LoadDoc(vValue) {
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "player.xml",true);
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4) {
Answer(xmlhttp.responseXML, vValue);
}
}
xmlhttp.send(null);
}
function Answer(doc, ParamValue) {
var counts=doc.getElementsByTagName("forward");
for(var i=0;i < counts.length; i++){
alert(counts.length)
var vname = counts[i].getElementsByTagName('name');
alert(vname[i].firstChild.nodeValue)
var vstats = counts[i].getElementsByTagName('stats');
alert(vstats[i].firstChild.nodeValue);
if (vname[i].firstChild.nodeValue == ParamValue)
{
alert(stats[i].firstChild.nodeValue);
}
}
}
</script>
</head>
<body>
<form>
<input type="field" id="champ" />
<input type="button"
onclick="javascript:LoadDoc(document.getElementById('champ').value);" />
</form>
</body>
</html>
The first ALERT is good finding 4 elements
the second ALERT works giving me JOE.
The third ALERT works giving me 45 (the number) of the stats of the first forward
But strangely, the alert are launch only once... I don't have 4 times the Alert, why it doesn''t turn 4 times inside the loop ?
Any Idea of what's wrong ?
Or a better solution to find the stats ?
Look at the console for any error messages. At a glance, the line alert(stats[i].firstChild.nodeValue); references an undeclared variable stats, so if that line executes, the script should throw a ReferenceError and terminate, which would cause the alerts to fire only once.
Thanks Dagg Nabbit, finally I found it. with the error found previously, I suppose that the vname[i] doesn't exist, so I replace the "i" with "0" so it's now vname[0]. For sure I'm looking the first element named "name" and not the second.I replace the vstats[i] with vstat[0] and it works perfectly.
I don't know if I'm having a syntax error but the compiler is giving me
TypeError: 'undefined' is not an object (evaluating
'xmlDoc.getElementsByTagName("icon")[count].childNodes')
Its me giving me this problem when im parsing the XML from my server, my actual javascript code is like this
var xmlDoc = Obj.responseXML;
var count = 0;
if(xmlDoc){
while(count <= xmlDoc.getElementsByTagName("item").length){
document.getElementById("flow").innerHTML += "<div class='item'><img class='content' src='" + xmlDoc.getElementsByTagName("icon")[count].childNodes[0].nodeValue.replace(/\s+$/g,' ') +"' /></div>";
count++;
}
}else{
alert("Unable to parse!");
}
and my XML goes like this.
<feed>
<item>
<title>Given Title</title>
<icon>
http://i178.photobucket.com/albums/w255/ace003_album/Logo-ETC-RGB-e1353503652739.jpg
</icon>
</item>
<item>...</item>
<item>...</item>
<item>...</item>
<item>...</item>
<item>...</item>
<item>...</item>
</feed>
i just want to parse the image link and to show it.
DOM parser
var url = "http://myURL.com/document.xml";
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
Obj = new XMLHttpRequest();
}
else
{
Obj = new ActiveXObject("Microsoft.XMLHTTP");
}
Obj.open("POST",url,false);
Obj.setRequestHeader("Content-type","application/x-www-form-urlencoded");
Obj.send();
Demo
Firstly, you're while loop condition should be just < not <=. By using the latter, the loop is running one too many times, causing the error because the index is out of bounds.
Secondly, in the while loop you're getting the icon elements based on the count from the root of the document. The icon's are children of each item so you should retrieve the icon relative to the item by using item.getElementsByTagName('icon')[0] not xmlDoc.getElementsByTagName('icon')[count].
Not related to the problem but building HTML as strings like that is undesirable. Creating the elements and inserting them into the DOM would be better because you don't need to handle any escaping. Also, store a reference to flow before the while, instead of finding it on each iteration.
var div;
var img;
var flow = document.getElementById('flow');
var items = xmlDoc.getElementsByTagName("item");
while(count < items.length){
div = document.createElement('div');
div.className = 'item';
img = document.createElement('img');
img.className = 'content';
img.src = items[count].getElementsByTagName("icon")[0].childNodes[0].nodeValue.replace(/\s+$/g,' ');
div.appendChild(img);
flow.appendChild(div);
count++;
}
Here's my code:
<html>
<header>
<title>Checkup Date</title>
<script type="text/javascript">
function datechange() {
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest(); }
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject
("Microsoft.XMLHTTP");
}
var tr = getElementsById(nameUpdate)
var tds = tr.getElementsByTagName('td');
var user = "";
var date = "";
for(var i = 0, len = tds.length; i < len; ++i) {
user = tds[0];
date = tds[3];
}
var url = "changedate.psp"
var params = "user=" + user + "&date=" + date;
xmlhttp.open("GET", url + "?" + params, true);
xmlhttp.send();
xmlDoc=xmlhttp.responseXML;
}
</script>
</header>
<body>
<%
Python that doesn't matter
%>
<%= More Python %>
</body>
</html>
My outputted HTML:
<tr id="TL-D03">
<td>nobody</td>
<td>TL-D03</td>
<td>2010-01-01</td>
<td>
<input type="checkbox" onclick="var nameUpdate = 'TL-D03'; datechange();">
What am I doing wrong here? It says getElementById is undefined.
getElementById is a function of document:
var tr = document.getElementById("nameUpdate")
MDN: https://developer.mozilla.org/en/DOM/document.getElementById
Problem 1: you're calling getElementsById. IDs are unique: the function is getElementById. No s.
Problem 2: getElementById is not a global function. You need to call it on the document object:
var tr = document.getElementById(nameUpdate)
After all, your script could reference more than one document (for example, with an iframe), so you need to be explicit about where you expect the element to be.
Also try changing:
<input type="checkbox" onclick="var nameUpdate = 'TL-D03'; datechange();">
to this:
<input type="checkbox" onclick="datechange('TL-D03')">
and
function datechange() {
to this
function datechange(nameUpdate) {
makes more sence
It's document.getElementById(), not getElementsById(), as it only returns one element.
The latter would not be very useful, since id attributes must be unique within an HTML document.
you need to use document.getElementById("yourelementid")
The reason it doesn't work is that var scopes a variable to the function it is defined in, so it isn't readable outside the anonymous function assigned to the onclick handler.
In more general "wrongness" terms, passing data about using globals is generally a bad idea.
Pass it as an argument instead.
function datechange(nameUpdate) {
and
datechange('TL-D03');