0

Parsing XML with multiple nodes

I'm working on a widget that involves connecting to a web service and retrieving an xml file. I have it working fine when the result is an xml file with a single wrapper node. But when the xml has multiple parent nodes I'm having trouble parsing the xml into an array.

This is my code parsing a single xml file:
CODE
var poll = new Array();
if(request.status == 200){
var xmlResponse = request.responseXML;
poll['title'] = xmlResponse.evaluate( "string(s:Envelope/s:Body/GetPollByCodeResponse/GetPollByCodeResult/a:Poll/a:title)" );
poll['choices'] = xmlResponse.evaluate( "string(s:Envelope/s:Body/GetPollByCodeResponse/GetPollByCodeResult/a:Poll/a:choices)" );
poll['eid'] = xmlResponse.evaluate( "string(s:Envelope/s:Body/GetPollByCodeResponse/GetPollByCodeResult/a:Poll/a:eid)" );
}


How can I parse a xml file with multiple a:Poll nodes?
This is what I have so far (but I'm not sure exactly what javascript is available to be used with the tv widget):
CODE
var events = new Array();
if(request.status == 200){
var xmlResponse = request.responseXML.getElementsByTagName("s:Envelope/s:Body/GetEventsByNameResponse/GetEventsByNameResult")[0];
for(var i = 0; i < xmlResponse.childNodes.length(); i++){
var response = xmlResponse.getElementsByTagName("a:Event")[i];
events[i]['title'] = response.getElementsByTagName("a:name")[0].childNodes[0].nodeValue;
events[i]['description'] = response.getElementsByTagName("a:description")[0].childNodes[0].nodeValue;
events[i]['location'] = response.getElementsByTagName("a:location")[0].childNodes[0].nodeValue;
}
}

by
  • br
  • Feb 24, 2010
11 Replies
  • Hi,
    I generally avoid parsing xml in my widgets, as it's expensive and tedious. Whenever I can, I'll write a php script or use a service such as Yahoo! Pipes to transform my xml into json and then deliver it to my widget.

    However, when I must, I'll generally do something like this:

    CODE
    if (xhr.status === 200) {
    var xml = xhr.responseXML,
    oItems = xml.evaluate("rss/channel/item/title"),
    oDescriptions = xml.evaluate("rss/channel/item/description"),
    arr = [];

    for (var i = 0, len = oItems.length; i < len; i++) {
    arr.push({
    title: oItems.item(i).firstChild.data,
    description: oDescriptions.item(i).firstChild.data,
    });
    }
    }


    The structure of the xml in this example is simple, but hopefully it gets the point across.

    - Ben
    0
  • QUOTE (Benjamin Toll @ Feb 26 2010, 02:00 PM) <{POST_SNAPBACK}>
    Hi,
    I generally avoid parsing xml in my widgets, as it's expensive and tedious. Whenever I can, I'll write a php script or use a service such as Yahoo! Pipes to transform my xml into json and then deliver it to my widget.

    However, when I must, I'll generally do something like this:

    CODE
    if (xhr.status === 200) {
    var xml = xhr.responseXML,
    oItems = xml.evaluate("rss/channel/item/title"),
    oDescriptions = xml.evaluate("rss/channel/item/description"),
    arr = [];

    for (var i = 0, len = oItems.length; i < len; i++) {
    arr.push({
    title: oItems.item(i).firstChild.data,
    description: oDescriptions.item(i).firstChild.data,
    });
    }
    }


    The structure of the xml in this example is simple, but hopefully it gets the point across.

    - Ben


    I'm a little bit confused on how to apply this to my problem.

    My XML file looks like this:
    CODE
    <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Header />
    <s:Body>
    <GetEventsByNameResponse xmlns="http://tempuri.org/">
    <GetEventsByNameResult xmlns:a="http://schemas.datacontract.org/2004/07/pollService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <a:Event>
    <a:name>Superbowl</a:name>
    <a:description>Big Football Event</a:description>
    <a:location>TBA</a:location>
    </a:Event>
    <a:Event>
    <a:name>Superbowl</a:name>
    <a:description>Big Football Event</a:description>
    <a:location>TBA</a:location>
    </a:Event>
    <a:Event>
    <a:name>Superbowl</a:name>
    <a:description>Big Football Event</a:description>
    <a:location>TBA</a:location>
    </a:Event>
    </GetEventsByNameResult>
    </GetEventsByNameResponse>
    </s:Body>
    </s:Envelope>


    CODE
    if (xhr.status === 200) {
    var xml = xhr.responseXML,
    oItems = xml.evaluate("s:Envelope/s:Body/GetEventsByNameResponse/GetEventsByNameResult"),
    events = [];

    for (var i = 0, len = oItems.length; i < len; i++) {
    events.push({
    title: oItems.item(i).firstChild[0].data,
    description: oItems.item(i).firstChild[1].data,
    location: oItems.item(i).firstChild[2].data,
    });
    }
    }


    How do I select the values for title, description, and location within the loop? The way you explained it doesn't quite make sense to me.
    0
  • QUOTE (br @ Feb 26 2010, 07:50 PM) <{POST_SNAPBACK}>
    How do I select the values for title, description, and location within the loop? The way you explained it doesn't quite make sense to me.


    Note that I altered your xpath query so it's returning the three Event nodes rather than the GetEventsByNameResult node.

    CODE
    if (xhr.status === 200) {
    var xml = xhr.responseXML,
    oItems = xml.evaluate("//a:Event"),
    events = [];

    for (var i = 0, len = oItems.length; i < len; i++) {
    events.push({
    name: oItems.item(i).firstChild.firstChild.data,
    description: oItems.item(i).firstChild.nextSibling.firstChild.data,
    location: oItems.item(i).firstChild.nextSibling.nextSibling.firstChild.data
    });
    }
    }


    Doing it the way I had in my previous post would change the example to look like this:

    CODE
    if (xhr.status === 200) {
    var xml = xhr.responseXML,
    oNames = xml.evaluate("//a:name"),
    oDescriptions = xml.evaluate("//a:description"),
    oLocations = xml.evaluate("//a:location"),
    events = [];

    for (var i = 0, len = oNames.length; i < len; i++) {
    events.push({
    name: oNames.item(i).firstChild.data,
    description: oDescriptions.item(i).firstChild.data,
    location: oLocations.item(i).firstChild.data
    });
    }
    }


    You then have what you need in a JavaScript array, so you can apply your application logic, whatever that is:

    CODE
    events.forEach(function (o) {
    log(o.name);
    log(o.description);
    log(o.location);
    });


    You see why converting your xml to json before it's sent to your widget makes your life so much easier? ;)- Ben
    0
  • QUOTE (Benjamin Toll @ Feb 27 2010, 02:14 AM) <{POST_SNAPBACK}>
    Note that I altered your xpath query so it's returning the three Event nodes rather than the GetEventsByNameResult node.

    CODE
    if (xhr.status === 200) {
    var xml = xhr.responseXML,
    oItems = xml.evaluate("//a:Event"),
    events = [];

    for (var i = 0, len = oItems.length; i < len; i++) {
    events.push({
    name: oItems.item(i).firstChild.firstChild.data,
    description: oItems.item(i).firstChild.nextSibling.firstChild.data,
    location: oItems.item(i).firstChild.nextSibling.nextSibling.firstChild.data
    });
    }
    }


    Doing it the way I had in my previous post would change the example to look like this:

    CODE
    if (xhr.status === 200) {
    var xml = xhr.responseXML,
    oNames = xml.evaluate("//a:name"),
    oDescriptions = xml.evaluate("//a:description"),
    oLocations = xml.evaluate("//a:location"),
    events = [];

    for (var i = 0, len = oNames.length; i < len; i++) {
    events.push({
    name: oNames.item(i).firstChild.data,
    description: oDescriptions.item(i).firstChild.data,
    location: oLocations.item(i).firstChild.data
    });
    }
    }


    You then have what you need in a JavaScript array, so you can apply your application logic, whatever that is:

    CODE
    events.forEach(function (o) {
    log(o.name);
    log(o.description);
    log(o.location);
    });


    You see why converting your xml to json before it's sent to your widget makes your life so much easier? ;)HI Ben, do you know, in the above code, how can I access the xml attribute?
    0
  • QUOTE (leicadbility @ Apr 12 2010, 09:42 PM) <{POST_SNAPBACK}>
    HI Ben, do you know, in the above code, how can I access the xml attribute?


    Hi leicadbility,
    Check out the XPath Support section in the documentation. It gives two different examples of how to extract an attribute node value.
    Also, since the engine supports XPath 1.0, if you'd like more information you can check out any xpath primer on the web to get a better understanding of using that language.

    - Ben
    0
  • QUOTE (Benjamin Toll @ Feb 26 2010, 02:00 PM) <{POST_SNAPBACK}>
    Hi,
    I generally avoid parsing xml in my widgets, as it's expensive and tedious. Whenever I can, I'll write a php script or use a service such as Yahoo! Pipes to transform my xml into json and then deliver it to my widget.

    However, when I must, I'll generally do something like this:

    CODE
    if (xhr.status === 200) {
    var xml = xhr.responseXML,
    oItems = xml.evaluate("rss/channel/item/title"),
    oDescriptions = xml.evaluate("rss/channel/item/description"),
    arr = [];

    for (var i = 0, len = oItems.length; i < len; i++) {
    arr.push({
    title: oItems.item(i).firstChild.data,
    description: oDescriptions.item(i).firstChild.data,
    });
    }
    }


    The structure of the xml in this example is simple, but hopefully it gets the point across.

    - Ben


    Ah....found you! I'm looking for information on how you are using yahoo Pipes for XML 2 JSON.

    I have a site that I can fetch the XML from but I'd rather use JSON on my widget.

    I've played a little with Yahoo Pipes, but I cannot fetch the XML and show it!

    Maybe you can give me an overview on which pipes sources you are using as well as other modules.

    Is it worth it for the widget to convert the XML into JSON? I would be screwed if yahoo Pipes goes down.

    I'd appreciate it.

    Ray
    0
  • QUOTE (Joe @ Dec 28 2010, 08:49 AM) <{POST_SNAPBACK}>
    Ah....found you! I'm looking for information on how you are using yahoo Pipes for XML 2 JSON.

    I have a site that I can fetch the XML from but I'd rather use JSON on my widget.

    I've played a little with Yahoo Pipes, but I cannot fetch the XML and show it!

    Maybe you can give me an overview on which pipes sources you are using as well as other modules.

    Is it worth it for the widget to convert the XML into JSON? I would be screwed if yahoo Pipes goes down.

    I'd appreciate it.

    Ray

    Hi Ray,
    Sorry, I missed this and am just seeing it now. I've never had to use Yahoo! Pipes as I've always been able to use another web service that has encoded my xml as json. I merely mentioned it as another option to do the conversion.
    0
  • Actually, i'm not able to find the example on how to use xpath in the documentation, not even through the search, can you please provide the link?
    0
  • The problem is i'm trying to acces the value of an attribute of a node of a xml i parsed, the xml was parsed correctly since i printed it to the terminal and it shows it with no problem, the xpath result shows as DOMNodelist, so i think i'm getting the right item with the xpath but i can't find how to access the value of the attribute in the corresponding node.
    0
  • CODE
            //retrive dome node list.
    var name = doc.evaluate('//Name' );
    // Store values of attributes in an array.
    var namesArray = new Array();
    for(var i = 0;i < name.length;i++)
    {
    namesArray.push(name.item(i).firstChild.data);
    }


    Hope this helps.
    0
  • Thanks, i missed the .item() for getting the node, since it's differente from the normal way in JS
    0

Recent Posts

in General - Yahoo! TV Widgets