[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 979
  • Last Modified:

How to loop through xml nodes using javascript

I have created the following line of code:

          if ("<xsl:value-of select='//Pathway/PathwayNo/Item1/matrix/no6/score0'/>" == "red") {
          document.getElementById('optAM1Cell0ID').style.backgroundColor = "#FF0000";
          }else if ("<xsl:value-of select='//Pathway/PathwayNo/Item1/matrix/no6/score0'/>" == "yellow") {
          document.getElementById('optAM1Cell0ID').style.backgroundColor = "#FFFF00";
          }else {
          document.getElementById('optAM1Cell0ID').style.backgroundColor = "#FFFFFF";
          }

          if ("<xsl:value-of select='//Pathway/PathwayNo/Item1/matrix/no6/score1'/>" == "red") {
          document.getElementById('optAM1Cell1ID').style.backgroundColor = "#FF0000";
          }else if ("<xsl:value-of select='//Pathway/PathwayNo/Item1/matrix/no6/score1'/>" == "yellow") {
          document.getElementById('optAM1Cell1ID').style.backgroundColor = "#FFFF00";
          }else {
          document.getElementById('optAM1Cell1ID').style.backgroundColor = "#FFFFFF";
          }

Having a look at the xpath and where it says "score0" and on the second part it says "score1". So basically what I want to do is create a javscript where is loops the same line of code and changes the xpath at the bit where "score" and it adds the number on the end automatically producing score0,score1,score2 using the loop.

Remember this is xpath therefore is needs to pick up the values from the xml file. I need help on the code to do this.
0
dipster307
Asked:
dipster307
  • 14
  • 6
  • 6
1 Solution
 
abelCommented:
(please use the code-window for code snippets...)

Ehrm, you're comparing a string, which contains a piece of XSLT, with a string "red". That'll always fail. Where's your XSLT or XPath invocation code? Strings are not magically transformed into executing code.

When you're going to do client-side XSLT or XPath, first things you need to do is load your data as XML. Then you can use the XPath or XSLT functions to go through the nodes. Because this is different per browser, I suggest you have a look at the Sarissa library. It comes with easy-to-follow examples. Try them out and then see if that can help you. Take a few hours or days to learn XPath + XSLT before you really try to attempt it with JavaScript.

See: http://dev.abiss.gr/sarissa/
0
 
smwolkeCommented:
this code will store the values in an array.  you then can loop through the array and split the string to get the key:value pair.
var items = [
                    <xsl:for-each select="//Pathway/PathwayNo/Item1/matrix/no6/child::*[starts-with(local-name(self::node()),'score')]">
                    '<xsl:value-of select="substring-after(local-name(./self::node()), 'score')"/>:<xsl:value-of select="self::node()"/>',
                    </xsl:for-each>];
                    for(x in items){
                        alert(items[x]);
                    }

Open in new window

0
 
abelCommented:
@smwolke: I'm afraid you cannot mix literal XSLT code and literal JavaScript code just like that... And it doesn't get it executed either...
0
Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

 
smwolkeCommented:
I was assuming that his code excerpt was generating HTML with javascript from a transformation of XML by an XSL document.   For example in the code example first is the xml, second is the xsl.  the result of a transformation is a html with javascript.
<Pathway>
    <PathwayNo>
        <Item1>
            <matrix>
                <no6>
                    <score0>red</score0>
                    <score1>green</score1>
                    <score2>blue</score2>
                    <score3>black</score3>
                    <score12>blue</score12>
                    <score13>black</score13>
                </no6>
            </matrix>
        </Item1>
    </PathwayNo>
</Pathway>


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="html"/>

    <xsl:template match="/">
        <html>
            <head>
                <title>xpath</title>
                <script>
                    var items = [ 
                    <xsl:for-each select="//Pathway/PathwayNo/Item1/matrix/no6/child::*[starts-with(local-name(self::node()),'score')]"> 
                    '<xsl:value-of select="substring-after(local-name(./self::node()), 'score')"/>:<xsl:value-of select="self::node()"/>', 
                    </xsl:for-each>]; 
                    for(x in items){ 
                        alert(items[x]); 
                    }
                </script>
            </head>
            <body>
                Got Alerts I hope.
            </body>
        </html>
    </xsl:template>

</xsl:stylesheet>

Open in new window

0
 
abelCommented:
ah, that would make sense. Then the title "using javascript" is actually the reverse: "how to output javascript with XSLT".

Tx for explaining, I really saw this from another angle ;-)
0
 
dipster307Author Commented:
Yep the comment made by:

ID:26305839Author:smwolkeDate:13/01/10 08:59 AM

is what I am looking for, but now I am trying understand the coding, the array where it the code state "substring-after" and "child::". This looks like advance xpath, which I havent done before any one got useful notes.
0
 
dipster307Author Commented:
<Pathway>
    <PathwayNo>
        <Item1>
            <matrix>
                <no6>
                    <score0>red</score0>
                    <score1>green</score1>
                    <score2>blue</score2>
                    <score3>black</score3>
                    <score12>blue</score12>
                    <score13>black</score13>
                </no6>
            </matrix>
        </Item1>
        <Item2>
            <matrix>
                <no6>
                    <score0>red</score0>
                    <score1>green</score1>
                    <score2>blue</score2>
                    <score3>black</score3>
                    <score12>blue</score12>
                    <score13>black</score13>
                </no6>
            </matrix>
        </Item2>
    </PathwayNo>
</Pathway>


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="html"/>

    <xsl:template match="/">
        <html>
            <head>
                <title>xpath</title>
                <script>
                    var items = [
                    <xsl:for-each select="//Pathway/PathwayNo/Item1/matrix/no6/child::*[starts-with(local-name(self::node()),'score')]">
                    '<xsl:value-of select="substring-after(local-name(./self::node()), 'score')"/>:<xsl:value-of select="self::node()"/>',
                    </xsl:for-each>];
                    for(x in items){
                        alert(items[x]);
                    }
                </script>
            </head>
            <body>
                Got Alerts I hope.
            </body>
        </html>
    </xsl:template>

</xsl:stylesheet>


Looking back at the code, I have added more data to the xml, because this is the bit my org. point was. If there are two "Items" (see xml). I need to be able to do something like below:

<xsl:for-each select="//Pathway/PathwayNo/Item[y]/matrix/no6/score[x]>

So looping through the paths without repeat coding over and over again.
0
 
abelCommented:
Repeat: "please use the code-window for code snippets..."

With that I meant: click the Code-link, paste your code there, so it gets attached to your comment. This makes it more readable and easier to cut and paste and long lines will not be broken anymore.

I'll leave the answering of your last q. to smwolke, as I'm not sure about his code and your request and he knows his code best ;-)
0
 
smwolkeCommented:
For information on the syntax i used see:

http://www.w3.org/TR/1999/REC-xpath-19991116

Regarding your requirement,  the original post did not state that Item1 would have multiple siblings.  This makes the problem a little more difficult and would require more information.  Does Item[y] have unbounded siblings?  Does Score[x] have unbounded siblings?  Is x always sequential? Is y always sequential?  Can no6 have a sibling no5 that needs to be looped over?

Sorry about all the questions but I want to make sure that I am not trying to hit a moving target.
0
 
dipster307Author Commented:
basically if item7 is selected then it needs to select data from the xml where it matches the node item7. Then it checks the color, so if I select the score 2, it needs to collect the data from the xml to pick up the color, where the node is score2.

so in coding terms:

for (i=0; i<22; i++)  "There are 21 items, ie 21 nodes <Item1>,<Item2>etc.."
{
if (myItem == i) {
 <xsl:for-each select="//Pathway/PathwayNo/Item[i]">
0
 
dipster307Author Commented:
basically if item7 is selected then it needs to select data from the xml where it matches the node item7. Then it checks the color, so if I select the score 2, it needs to collect the data from the xml to pick up the color, where the node is score2.

so in coding terms:

for (i=0; i<22; i++)  "There are 21 items, ie 21 nodes <Item1>,<Item2>etc.."
{
if (myItem == i) {
 <xsl:for-each select="//Pathway/PathwayNo/Item[i]">
0
 
dipster307Author Commented:
basically if item7 is selected then it needs to select data from the xml where it matches the node item7. Then it checks the color, so if I select the score 2, it needs to collect the data from the xml to pick up the color, where the node is score2.

so in coding terms:

for (i=0; i<22; i++)  "There are 21 items, ie 21 nodes <Item1>,<Item2>etc.."
{
if (myItem == i) {
 <xsl:for-each select="//Pathway/PathwayNo/Item[i]">
0
 
dipster307Author Commented:
ignore the last 3 comments it was a mistake as I didnt finish my message.

basically if item7 is selected then it needs to select data from the xml where it matches the node item7. Then it checks the color, so if I select the score 2, it needs to collect the data from the xml to pick up the color, where the node is score2.

so in coding terms see below.


for (i=0; i<22; i++)  "There are 21 items, ie 21 nodes <Item1>,<Item2>etc.."
{
if (myItem == i) {
 <xsl:for-each select="//Pathway/PathwayNo/Item[i]">
for (y=0; y<5; y++) { 
if (myscore == y) {
<xsl:value-of select="matrix/no6/score[y]>
}
}
}

Open in new window

0
 
dipster307Author Commented:
or the best way to explain is each <Item> node has a child node <name> and you want a alert box to display the names for each <Item> node

<nodetest>
<item1>
<name>testing1</name>
</item1>
<item2>
<name>super2</name>
</item2>
<item3>
<name>cool3</name>
</item3>
</nodetest>

for (i=0; i<4; i++) {
<xsl:value-of select='//Pathway/PathwayNo/Item " + i + "/name'/>
}

this is what I am trying to do, but then within this loop is the score as well like a loop in a loop. The above doesnt work because you cant use xpath in that way?
0
 
dipster307Author Commented:
or the best way to explain is each <Item> node has a child node <name> and you want a alert box to display the names for each <Item> node

<nodetest>
<item1>
<name>testing1</name>
</item1>
<item2>
<name>super2</name>
</item2>
<item3>
<name>cool3</name>
</item3>
</nodetest>

for (i=0; i<4; i++) {
<xsl:value-of select='//Pathway/PathwayNo/Item " + i + "/name'/>
}

this is what I am trying to do, but then within this loop is the score as well like a loop in a loop. The above doesnt work because you cant use xpath in that way?
0
 
dipster307Author Commented:
or the best way to explain is each <Item> node has a child node <name> and you want a alert box to display the names for each <Item> node

<nodetest>
<item1>
<name>testing1</name>
</item1>
<item2>
<name>super2</name>
</item2>
<item3>
<name>cool3</name>
</item3>
</nodetest>

for (i=0; i<4; i++) {
<xsl:value-of select='//Pathway/PathwayNo/Item " + i + "/name'/>
}

this is what I am trying to do, but then within this loop is the score as well like a loop in a loop. The above doesnt work because you cant use xpath in that way?
0
 
abelCommented:
Three times the same comment??? Then again three times the same comment... hmm...
0
 
smwolkeCommented:
Three times is a charm, I guess!

The code above, in your post, will not work because the xpath will be evaluated at the time the transformation takes place and the javascript will be evaluated on the client side.  You could build a multidimensional array to store all values from the nodes for processing when it reaches the client side.  May I ask why you are trying change color on the client side with javascript and not setting it during transformation with a template, which is alot easier?
0
 
smwolkeCommented:
Something like this is what I meant.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="html"/> 
    <xsl:template match="/"> 
        <html> 
            <head> 
                <title>xpath</title> 
                <script> 
                    var items = [  
                    <xsl:for-each select="//Pathway/PathwayNo/child::*[starts-with(local-name(self::node()),'Item')]">  
                    '<xsl:value-of select="substring-after(local-name(./self::node()), 'Item')"/>',  
                    </xsl:for-each>];  
                    var scores = [  
                    <xsl:for-each select="//Pathway/PathwayNo/child::*[starts-with(local-name(self::node()),'Item')]">  
                    [
                        <xsl:for-each select="//Pathway/PathwayNo/Item1/matrix/no6/child::*[starts-with(local-name(self::node()),'score')]">  
                    '<xsl:value-of select="substring-after(local-name(./self::node()), 'score')"/>:<xsl:value-of select="self::node()"/>',  
                        </xsl:for-each>,
                    ],
                    </xsl:for-each>
                    ];  
                    
                    <![CDATA[
                    <!--
                    var color;
                    var score_num;
                    for(x in items){
                        for(y in scores[x]){
                            score_num = scores[x][y].split(":")[0];
                            color = scores[x][y].split(":")[1];
                            document.write("document.getElementById('optAM" + items[x] + "Cell" + score_num + "ID').style.backgroundColor = " + color);
                            document.write("<br/>");
                        }
                    }
                    -->
                     ]]>
                </script> 
            </head> 
            <body> 
            </body> 
        </html> 
    </xsl:template> 
</xsl:stylesheet>

Open in new window

0
 
dipster307Author Commented:
I am sure the comment made by "ID:26315691Author:smwolkeDate:14/01/10 08:30 AM", works.

XML:

    <nodetest>
      <item1>
        <name>testing1</name>
        <description>des testing1</description>
      </item1>
      <item2>
        <name>super2</name>
        <description>des super2</description>
      </item2>
      <item3>
        <name>cool3</name>
        <description>des cool3</description>
      </item3>
    </nodetest>


But its a bit to complex, then the one I finally managed to work out.

Firstly read the xml file:

          xmlRead = new ActiveXObject("Microsoft.XMLDOM");
          xmlRead.async=false;
          xmlRead.load("../XML/XMLExample.xml");

Then looping through the xml collecting data, by the user match:

          for (k=1; k<22; k++) {

          if (objMatch1.value==k) {

          xpathItem = xmlRead.getElementsByTagName("Item" + k + "/name");
          for (i=0;i<xpathItem.length;i++) {
          itemDetails = xpathItem[i].lastChild.nodeValue;
          }
          xDocForm.match1PathwayLabelID.value = itemDetails;

          xpathItem = xmlRead.getElementsByTagName("Item" + k + "/description");
          for (i=0;i<xpathItem.length;i++) {
          itemDetails = xpathItem[i].lastChild.nodeValue;
          }
          xDocForm.optADescription.value = itemDetails;
}

This works just fine, and your using up extra memory by creating arrays. What you think "smwolke", works well right????????

0
 
dipster307Author Commented:
I am sure the comment made by "ID:26315691Author:smwolkeDate:14/01/10 08:30 AM", works.

XML:

    <nodetest>
      <item1>
        <name>testing1</name>
        <description>des testing1</description>
      </item1>
      <item2>
        <name>super2</name>
        <description>des super2</description>
      </item2>
      <item3>
        <name>cool3</name>
        <description>des cool3</description>
      </item3>
    </nodetest>


But its a bit to complex, then the one I finally managed to work out.

Firstly read the xml file:

          xmlRead = new ActiveXObject("Microsoft.XMLDOM");
          xmlRead.async=false;
          xmlRead.load("../XML/XMLExample.xml");

Then looping through the xml collecting data, by the user match:

          for (k=1; k<22; k++) {

          if (objMatch1.value==k) {

          xpathItem = xmlRead.getElementsByTagName("Item" + k + "/name");
          for (i=0;i<xpathItem.length;i++) {
          itemDetails = xpathItem[i].lastChild.nodeValue;
          }
          xDocForm.match1PathwayLabelID.value = itemDetails;

          xpathItem = xmlRead.getElementsByTagName("Item" + k + "/description");
          for (i=0;i<xpathItem.length;i++) {
          itemDetails = xpathItem[i].lastChild.nodeValue;
          }
          xDocForm.optADescription.value = itemDetails;
}

This works just fine, and your using up extra memory by creating arrays. What you think "smwolke", works well right????????

0
 
dipster307Author Commented:
I am sure the comment made by "ID:26315691Author:smwolkeDate:14/01/10 08:30 AM", works.

XML:

    <nodetest>
      <item1>
        <name>testing1</name>
        <description>des testing1</description>
      </item1>
      <item2>
        <name>super2</name>
        <description>des super2</description>
      </item2>
      <item3>
        <name>cool3</name>
        <description>des cool3</description>
      </item3>
    </nodetest>


But its a bit to complex, then the one I finally managed to work out.

Firstly read the xml file:

          xmlRead = new ActiveXObject("Microsoft.XMLDOM");
          xmlRead.async=false;
          xmlRead.load("../XML/XMLExample.xml");

Then looping through the xml collecting data, by the user match:

          for (k=1; k<22; k++) {

          if (objMatch1.value==k) {

          xpathItem = xmlRead.getElementsByTagName("Item" + k + "/name");
          for (i=0;i<xpathItem.length;i++) {
          itemDetails = xpathItem[i].lastChild.nodeValue;
          }
          xDocForm.match1PathwayLabelID.value = itemDetails;

          xpathItem = xmlRead.getElementsByTagName("Item" + k + "/description");
          for (i=0;i<xpathItem.length;i++) {
          itemDetails = xpathItem[i].lastChild.nodeValue;
          }
          xDocForm.optADescription.value = itemDetails;
}

This works just fine, and your using up extra memory by creating arrays. What you think "smwolke", works well right????????

0
 
abelCommented:
Just a general question: three times when you posted a comment, you added it three times (totaling 6 doubled comments). Is that on purpose to attract attention? Please try to add comments only once. We will see them, we will get notified so really, one is enough...
0
 
smwolkeCommented:
Regarding the memory usage, I think that if the xslt transformation was done on the server, you would be using less memory with the arrays on the client side.  I say this because your current solution is pulling the whole xml document into a DOM object on the client side and the arrays only were only holding a subset of the xml data.  Your solution assumes that you know the upper limit of the items(k<22) and that the numbers were sequential(i++).  I asked if this were the case but the question was never answered; my solution will cover unknown quantities of bounded items and non sequential items which is why it may seem more complex.  Also your solution not is relevant to xpath.

Just some thoughts.
0
 
dipster307Author Commented:
thanks for the info from snwolke.

Regarding the posting my comment three times, IT'S NOT ME. I click on sumbit and for strange reason 3 comments are posted, its the website issue, nothing to do with me.
0
 
dipster307Author Commented:
Didnt state the question clearly, hence why the solution was slightly different to what I was looking for. However the solution does work.
0

Featured Post

Learn to develop an Android App

Want to increase your earning potential in 2018? Pad your resume with app building experience. Learn how with this hands-on course.

  • 14
  • 6
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now