By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,257 Members | 925 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,257 IT Pros & Developers. It's quick & easy.

<Need Help>How to throw an error based on node count in XSLT?

P: 17
Hi,
I have the following XML snippet:

Expand|Select|Wrap|Line Numbers
  1. <root>
  2.  
  3. <template1>
  4. <elem1>1000</elem1>
  5. <elem2>
  6.     <subelem1>65</subelem1>
  7. </elem2>
  8.  </template1>
  9.  
  10. <template1>
  11. <elem1>2000</elem1>
  12. <elem2>
  13. <subelem1>45</subelem1>
  14. </elem2>
  15. </template1>
  16.  
  17. <template2>
  18. <type1>
  19.  <tag1>1000</tag1>
  20. </type1>
  21.  
  22. <type1>
  23. <tag1>1000</tag1>
  24. </type1>
  25.  
  26. <type1>
  27. <tag1>1000</tag1>
  28. </type1>
  29.  
  30. <type1>
  31.  <tag1>2000</tag1>
  32.  </type1>
  33.  
  34. <type1>
  35. <tag1>2000</tag1>
  36. </type1>
  37.  
  38. <type1>
  39. <tag1>2000</tag1>
  40. </type1>
  41.  
  42. </template2>
  43. </root>
  44.  
  45.  
In the above code,there are 3 <tag1> elements whose value is 1000 and 3 <tag1> elements whose value is 2000.
The value of subelem1 = 65(for which the elem1 is 1000)
The value of subelem1 = 45(for which the elem1 is 2000)

Now the requirement is:
1.There should be only 2 <tag1> elements if subelem1 >60(in this case we have to get the subelem1 value by comparing the <tag1>=<elem1>.Here it is 1000).otherwise error has to be thrown.

2.There should be only 1 <tag1> element if subelem1 <60(in this case we have to get the subelem1 value by comparing the <tag1>=<elem1>.Here it is 2000).otherwise error has to be thrown.

Using your XSLT code that you replied to my previous question,when i print the count in error message it is giving the total count as 6 where as we have to get the count as 3 for <tag1>=1000

Please help me,how can we do the above requirement.

Thanks,
Sep 16 '08 #1
Share this Question
Share on Google+
16 Replies


jkmyoung
Expert 100+
P: 2,057
Can you post the previous code?
It's probably as easy as adding a condition[elem1=$value]
Sep 16 '08 #2

P: 17
Hi Young,
I tried the following code:

Expand|Select|Wrap|Line Numbers
  1. <xsl:variable name="rules" select="count(/template2/type1[tag1 = /template1/elem1])"/>
  2. <xsl:if test="/template1/elem2/subelem1 >60 and $rules >2">
  3. <xsl:message terminate="yes">
  4. <xsl:value-of select="concat("Only 2 tags are allowed for tag1 =1000")/>
  5. </xsl:if>
  6. </xsl:if>
  7.  
The problem with this code is it is giving the total count for variable rules as 6 where as we have to get the count as 3 for <tag1>=1000.The condition to evaluate rules is selecting all the <tag1> nodes and giving count as 6.How to solve this?

Also please note that there will be 10 <template1> nodes.I have to check across all <template1> tags.

Thanks,
Sep 16 '08 #3

jkmyoung
Expert 100+
P: 2,057
Assuming you're in template:
<xsl:template match="/root/template1/elem1/subelem1">
The value you want for each one is in relative path: ../../elem1
Expand|Select|Wrap|Line Numbers
  1. <xsl:variable name="elem1" select="../../elem1"/>
  2. <xsl:variable name="rules" select="count(/template2/type1[tag1 = $elem1])"/>
  3. .......
  4. <xsl:value-of select="concat('Only 2 tags are allowed for tag1 =',$elem1)"/>
  5.  
Sep 16 '08 #4

P: 17
Hi Young,
Do you mean to say :

Expand|Select|Wrap|Line Numbers
  1. <xsl:template match="/root/template1/elem1/subelem1[. &gt; 60]">
  2. <xsl:variable name="elem1" select="../../elem1"/>
  3. <xsl:variable name="rules" select="count(/template2/type1[tag1 = $elem1])"/>
  4. <xsl:if test="$rules &gt; 2">
  5. <xsl:message terminate="yes">
  6. <xsl:value-of select="concat("Only 2 tags are allowed for tag1 = ', $elem1)")/>
  7. </xsl:if>
  8. </xsl:template>
  9.  
The above code is not working.
In the template match we have to select all <template1> whose <subelem1> value is > 60,so i changed the template match.is it ok?
whatelse has to be changed in the above code to make it working?

Thanks,


Assuming you're in template:
<xsl:template match="/root/template1/elem1/subelem1">
The value you want for each one is in relative path: ../../elem1
Expand|Select|Wrap|Line Numbers
  1. <xsl:variable name="elem1" select="../../elem1"/>
  2. <xsl:variable name="rules" select="count(/template2/type1[tag1 = $elem1])"/>
  3. .......
  4. <xsl:value-of select="concat('Only 2 tags are allowed for tag1 =',$elem1)"/>
  5.  
Sep 16 '08 #5

Dormilich
Expert Mod 5K+
P: 8,639
Expand|Select|Wrap|Line Numbers
  1. <xsl:template match="/root/template1/elem1/subelem1[. &gt; 60]">
  2. <xsl:variable name="elem1" select="../../elem1"/>
  3. <xsl:variable name="rules" select="count(/template2/type1[tag1 = $elem1])"/>
  4. <xsl:if test="$rules &gt; 2">
  5. <xsl:message terminate="yes">
  6. <xsl:value-of select="concat("Only 2 tags are allowed for tag1 = ', $elem1)")/>
  7. </xsl:if>
  8. </xsl:template>
  9.  
The above code is not working.
In the template match we have to select all <template1> whose <subelem1> value is > 60,so i changed the template match.is it ok?
whatelse has to be changed in the above code to make it working?
line #1: "//template1[elem2/subelem1 &gt; 60]" (ok I shifted the condition a bit, but that's only to look better... adjust $elem1 accordingly)

in the above code you're not selecting <template1> but <subelem1>

line #3: /root/template2/type1[tag1 = $elem1] or //template2/type1[tag1 = $elem1]

line #5: element not closed

line #6: typing mistake, 2nd quotation mark must be ' not "

regards
Sep 16 '08 #6

P: 17
Hi Dormilich,
Thanks a lot.Its working perfectly.

line #1: "//template1[elem2/subelem1 &gt; 60]" (ok I shifted the condition a bit, but that's only to look better... adjust $elem1 accordingly)

in the above code you're not selecting <template1> but <subelem1>

line #3: /root/template2/type1[tag1 = $elem1] or //template2/type1[tag1 = $elem1]

line #5: element not closed

line #6: typing mistake, 2nd quotation mark must be ' not "

regards
Sep 17 '08 #7

Dormilich
Expert Mod 5K+
P: 8,639
glad I could be of help
Sep 17 '08 #8

P: 17
Hi Dormilich,

The following is the code you suggested for my question:

<xsl:template match="/root/template1[elem2/subelem1 &gt; 60]">
<xsl:variable name="elem1" select="elem1"/>
<xsl:variable name="rules" select="count(/root/template2/type1[tag1 = $elem1])"/>
<xsl:if test="$rules &gt; 2">
<xsl:message terminate="yes">
<xsl:value-of select="concat("Only 2 tags are allowed for tag1 = ', $elem1)')/>
</xsl:if>
</xsl:template>

It is working fine but in one scenario this is not working.I changed 45 to 75 value for subelem1.The $rules in the code is selecting the count for each subelem1 but I want to throw the error if the count is > 2 for all the subelem1 whose value is > 60.Please note that there can be any number of <template1> tags.

In the following code,(according to your code) it works fine as there are only two <tag1> tags for each subelem1 but I want to throw error after combining the count for all the <subelem1> tags whose value is > 60.

So it has to throw error for the following input saying that "The combined total count is 4.Only 2 <tag1> are allowed under <template2>"


Expand|Select|Wrap|Line Numbers
  1. <root>
  2.  
  3. <template1>
  4. <elem1>1000</elem1>
  5. <elem2>
  6.     <subelem1>65</subelem1>
  7. </elem2>
  8.  </template1>
  9.  
  10. <template1>
  11. <elem1>2000</elem1>
  12. <elem2>
  13. <subelem1>75</subelem1>
  14. </elem2>
  15. </template1>
  16.  
  17. <template2>
  18. <type1>
  19.  <tag1>1000</tag1>
  20. </type1>
  21.  
  22. <type1>
  23. <tag1>1000</tag1>
  24. </type1>
  25.  
  26. <type1>
  27.  <tag1>2000</tag1>
  28. </type1>
  29.  
  30. <type1>
  31.  <tag1>2000</tag1>
  32. </type1>
  33.  
  34. </template2>
  35.  
Please help me in adding this extra check for the code you suggested.
Thanks.
glad I could be of help
Oct 6 '08 #9

jkmyoung
Expert 100+
P: 2,057
Xpath for values (>60?) you're looking at is /root/template1/elem2/subelem1

Find all the template 1 nodes with that value > 60
/root/template1[elem2/subelem1 &gt; 60]

Now we find each of the indexes for these values > 60, eg the elem1 node.
/root/template1[elem2/subelem1 &gt; 60]/elem1

general xpath for type1's tag1 values.
/root/template2/type1/tag1

The ones meeting the criteria are:
(/root/template2/type1/tag1[/root/template1[elem2/subelem1 &gt; 60]/elem1 = .]
In other words, there exists a template1 node with subelem1 > 60, such that the elem1 node equals the current tag1 node.

Putting it together, it should look like:
Expand|Select|Wrap|Line Numbers
  1. <xsl:template match="/root">
  2.     <xsl:if test="count(/root/template2/type1/tag1[/root/template1[elem2/subelem1 &gt; 60]/elem1 = .] ) &gt; 2">
  3.         <xsl:message terminate="yes">
  4.             <xsl:value-of select="'Only 2 tags are allowed for tag1 &gt; 60 '"/>
  5.         </xsl:message>
  6.     </xsl:if>
  7. </xsl:template>
  8.  
  9.  
Oct 6 '08 #10

Dormilich
Expert Mod 5K+
P: 8,639
I understand it so, that the count of <tag1> has to be now less than 3 if any <subelem1> is > 60 (although this will kill the condition <tag1> = <elem1>). so it should be an easier expression now.
Expand|Select|Wrap|Line Numbers
  1. <xsl:if test="count(//subelem1[. &gt; 60]) and count(//tag1) &gt; 2">
  2.   <xsl:message terminate="yes">
  3.   <xsl:text>Only 2 tags are allowed for tag1</xsl:text>
  4. </xsl:if>
please correct me, if my understanding of the conditions is wrong
The ones meeting the criteria are:
/root/template2/type1/tag1[[/root/template1[elem2/subelem1 &gt; 60]/elem1] = .]
In other words, there exists a template1 node with subelem1 > 60, such that the elem1 node equals the current tag1 node.
I don't think this will work in the intended way since [expression] will always return true or false.

regards
Oct 6 '08 #11

jkmyoung
Expert 100+
P: 2,057
Edited above message after Dormilich's comment.
Oct 6 '08 #12

Dormilich
Expert Mod 5K+
P: 8,639
still the question remains, if the condition <tag1> = <elem1> must be fulfilled. unfortunately, that's not clear from the actual question. (this was the case for the original question)
Oct 6 '08 #13

P: 17
Hi young,
Thanks for the mail.
The explanation you gave seems to be logically perfect but when I executed this,I am encountering an error saying the "XPath error : Invalid expression"

Please suggest me.


Xpath for values (>60?) you're looking at is /root/template1/elem2/subelem1

Find all the template 1 nodes with that value > 60
/root/template1[elem2/subelem1 &gt; 60]

Now we find each of the indexes for these values > 60, eg the elem1 node.
/root/template1[elem2/subelem1 &gt; 60]/elem1

general xpath for type1's tag1 values.
/root/template2/type1/tag1

The ones meeting the criteria are:
(/root/template2/type1/tag1[/root/template1[elem2/subelem1 &gt; 60]/elem1 = .]
In other words, there exists a template1 node with subelem1 > 60, such that the elem1 node equals the current tag1 node.

Putting it together, it should look like:
Expand|Select|Wrap|Line Numbers
  1. <xsl:template match="/root">
  2.     <xsl:if test="count(/root/template2/type1/tag1[/root/template1[elem2/subelem1 &gt; 60]/elem1 = .] ) &gt; 2">
  3.         <xsl:message terminate="yes">
  4.             <xsl:value-of select="'Only 2 tags are allowed for tag1 &gt; 60 '"/>
  5.         </xsl:message>
  6.     </xsl:if>
  7. </xsl:template>
  8.  
  9.  
Oct 7 '08 #14

P: 17
Hi Dormilich,
what you said is correct.The condition <tag1> = <elem1> has also to be fulfilled.

To make more clear on my question:
In the XML code mentioned in comment # 9:
a) There are 2 <type1> tags whose <tag1> value = <elem1> (that is 1000)
b) There are 2 <type1> tags whose <tag1> value = <elem1> (that is 2000)
Individual count is 2 where as the combined count is 4(error has to be thrown for this also as the total count is greater than 2)

In both the above cases <subelem1> is greater than 60 for each <template1> under which the <elem1> is 1000,2000.

Now the requirement is :
The error has to be thrown in two cases:
1.If the count of all the <tag1> = <elem1> and <subelem1 > 60 is greater than 2

2.If the total count of all the sets meeting the above criteria is greater than 2.

According to the code mentioned in comment # 9,if I add one more <type1> with <tag1> =1000,it throws error saying only 2 tags are allowed for <tag1> = <elem1> where as there are already 4 <type1> tags whose <tag1>= <elem1> but with different <subelem1> values >60.

I guess I made my question clearly.

Thanks,

still the question remains, if the condition <tag1> = <elem1> must be fulfilled. unfortunately, that's not clear from the actual question. (this was the case for the original question)
Oct 7 '08 #15

Dormilich
Expert Mod 5K+
P: 8,639
Now the requirement is :
The error has to be thrown in two cases:
1.If the count of all the <tag1> = <elem1> and <subelem1> > 60 is greater than 2

2.If the total count of all the sets meeting the above criteria is greater than 2.
wouldn't the 2nd requirement always include the 1st one (thus making it obsolete)?

The explanation you gave seems to be logically perfect but when I executed this,I am encountering an error saying the "XPath error : Invalid expression"
couldn't verify that, the expression was working perfectly, when I tried it.

regards
Oct 8 '08 #16

P: 17
Hi,
It worked well.

Thanks for your help.

wouldn't the 2nd requirement always include the 1st one (thus making it obsolete)?

couldn't verify that, the expression was working perfectly, when I tried it.

regards
Oct 21 '08 #17

Post your reply

Sign in to post your reply or Sign up for a free account.