0

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?

Adrian
  • 33
  • 2
  • 8
  • 1
    Any reason you don't want to use jQuery? The jquery get() function auto-parses xml for you, along with handling the XHR request: http://api.jquery.com/jQuery.get/ – David Hammond Nov 12 '14 at 21:29
  • A simple example of using the jQuery get function to parse XML: http://stackoverflow.com/questions/226663/parse-rss-with-jquery/7067582#7067582 – David Hammond Nov 12 '14 at 21:34
  • jQuery selectors do not support namespaces and are much slower and need a lot more memory. Problem is current IEs do not support Xpath at all, you need to use a JS implementation. – ThW Nov 12 '14 at 21:47
  • David, the issue with the example you showed is why I am using XPath: the subitems section makes it such that calling: $(data).find("item") returns a list of 4, since it includes the subitems, which I don't want parsed at this moment (they will be parsed later). ADASein, the weird thing is that iterateNext() isn't throwing an exception, I just get hit with the null pointer when I try to use the result of iterateNext(). – Adrian Nov 12 '14 at 21:54
  • Very simple. Just use $(data).find(">item") to get just the immediate children. I'm pretty sure CSS selectors can do everything XPath does, or at least everything you need to do in this example. – David Hammond Nov 12 '14 at 21:56
  • David, I tried playing around with that in the debugger without much success. Regardless, Xenos solved the issue below. I will have a better look into jQuery, however, since it seems to be a better way of going about much of what I'm trying to do. Thanks for your help. – Adrian Nov 12 '14 at 22:11

1 Answers1

3

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.

Xenos
  • 3,351
  • 2
  • 27
  • 50
  • 1
    Wow. I don't know how I missed that, especially considering I didn't make the mistake on the line immediately below it... I'll have to chalk that one up as tunnel-vision. Thanks for the help. – Adrian Nov 12 '14 at 22:10