accessing previous context inside apply-templates?

M

Mike Partridge

Is it possible to access your caller's (not parent) context while
inside a <xsl:template match...> or <xsl:for-each...>? Here is the xml
I'm using:

<report-set>
...<report>
.....<detail-data>
.......<detail-column position="1" dsc="col1" sum_fg="0"/>
.......<detail-column position="2" dsc="col2" sum_fg="1"/>
.......<detail-column position="3" dsc="col3" sum_fg="1"/>
.......<detail-column position="4" dsc="col4" sum_fg="1"/>
.......<detail-column position="5" dsc="col5" sum_fg="1"/>
.....</detail-data>
.....<invoice inv_id="232243">
.......<break level="1">
.........<break level="2">
...........<break level="3">
.............<detail>
...............<row>
.................<field position="1">Text1</field>
.................<field position="2">34</field>
.................<field position="3">3400.00</field>
.................<field position="4">0.00</field>
.................<field position="5">3400.00</field>
...............</row>
...............<row>
.................<field position="1">Text2</field>
.................<field position="2">96</field>
.................<field position="3">9600</field>
.................<field position="4">0.00</field>
.................<field position="5">9600.00</field>
...............</row>
.............</detail>
...........</break>
...........<break level="3">
.............<detail>
...............<row>
.................<field position="1">Text1</field>
.................<field position="2">13</field>
.................<field position="3">1300.00</field>
.................<field position="4">-1300.00</field>
.................<field position="5">0.00</field>
...............</row>
...............<row>
.................<field position="1">Text2</field>
.................<field position="2">13</field>
.................<field position="3">2600</field>
.................<field position="4">0.00</field>
.................<field position="5">2600.00</field>
...............</row>
.............</detail>
...........</break>
.........</break>
.......</break>
.....</invoice>
...</report>
</report-set>

When I am in the <break> context (of which there can be any number), I
want to output a sum of each field based on the <detail-data> from the
top. I've tried to apply-templates on the
/report-set/report/detail-data/detail-column which can give me a
column for each <detail-column>, but I need to sum from the context
where the apply-templates was called. Is this possible? I've hacked a
way by passing my context position and break level and going back to
look for the break i want, but it's inefficient and hard to read, not
to mention ugly.

Does anyone have any ideas? Please tell me there's an easier way!

Mike Partridge..
 
D

Dimitre Novatchev

Mike Partridge said:
Is it possible to access your caller's (not parent) context while
inside a <xsl:template match...> or <xsl:for-each...>? Here is the xml
I'm using:

<report-set>
..<report>
....<detail-data>
......<detail-column position="1" dsc="col1" sum_fg="0"/>
......<detail-column position="2" dsc="col2" sum_fg="1"/>
......<detail-column position="3" dsc="col3" sum_fg="1"/>
......<detail-column position="4" dsc="col4" sum_fg="1"/>
......<detail-column position="5" dsc="col5" sum_fg="1"/>
....</detail-data>
....<invoice inv_id="232243">
......<break level="1">
........<break level="2">
..........<break level="3">
............<detail>
..............<row>
................<field position="1">Text1</field>
................<field position="2">34</field>
................<field position="3">3400.00</field>
................<field position="4">0.00</field>
................<field position="5">3400.00</field>
..............</row>
..............<row>
................<field position="1">Text2</field>
................<field position="2">96</field>
................<field position="3">9600</field>
................<field position="4">0.00</field>
................<field position="5">9600.00</field>
..............</row>
............</detail>
..........</break>
..........<break level="3">
............<detail>
..............<row>
................<field position="1">Text1</field>
................<field position="2">13</field>
................<field position="3">1300.00</field>
................<field position="4">-1300.00</field>
................<field position="5">0.00</field>
..............</row>
..............<row>
................<field position="1">Text2</field>
................<field position="2">13</field>
................<field position="3">2600</field>
................<field position="4">0.00</field>
................<field position="5">2600.00</field>
..............</row>
............</detail>
..........</break>
........</break>
......</break>
....</invoice>
..</report>
</report-set>

When I am in the <break> context (of which there can be any number), I
want to output a sum of each field based on the <detail-data> from the
top. I've tried to apply-templates on the
/report-set/report/detail-data/detail-column which can give me a
column for each <detail-column>, but I need to sum from the context
where the apply-templates was called. Is this possible? I've hacked a
way by passing my context position and break level and going back to
look for the break i want, but it's inefficient and hard to read, not
to mention ugly.

Does anyone have any ideas? Please tell me there's an easier way!

Mike Partridge..


I am not sure what you exactly want, but if I guess well, this will answer
your question.

This transformation:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:eek:utput method="text"/>
<xsl:strip-space elements="*"/>

<xsl:key name="kDetail" match="detail-column" use="@position"/>

<xsl:template match="row">
<xsl:value-of select="sum(field[key('kDetail',
count(preceding-sibling::*)+1)/@sum_fg = 1])"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>



when applied on your source.xml:

<report-set>
<report>
<detail-data>
<detail-column position="1" dsc="col1" sum_fg="0"/>
<detail-column position="2" dsc="col2" sum_fg="1"/>
<detail-column position="3" dsc="col3" sum_fg="1"/>
<detail-column position="4" dsc="col4" sum_fg="1"/>
<detail-column position="5" dsc="col5" sum_fg="1"/>
</detail-data>
<invoice inv_id="232243">
<break level="1">
<break level="2">
<break level="3">
<detail>
<row>
<field position="1">Text1</field>
<field position="2">34</field>
<field position="3">3400.00</field>
<field position="4">0.00</field>
<field position="5">3400.00</field>
</row>
<row>
<field position="1">Text2</field>
<field position="2">96</field>
<field position="3">9600</field>
<field position="4">0.00</field>
<field position="5">9600.00</field>
</row>
</detail>
</break>
<break level="3">
<detail>
<row>
<field position="1">Text1</field>
<field position="2">13</field>
<field position="3">1300.00</field>
<field position="4">-1300.00</field>
<field position="5">0.00</field>
</row>
<row>
<field position="1">Text2</field>
<field position="2">13</field>
<field position="3">2600</field>
<field position="4">0.00</field>
<field position="5">2600.00</field>
</row>
</detail>
</break>
</break>
</break>
</invoice>
</report>
</report-set>

produces this output:

6834
19296
13
5213


In case my guess about the real meaning of your message was unsuccessful,
could you, please, describe it in a correct and unambiguous way?


Dimitre Novatchev.
FXSL developer, XML Insider,

http://fxsl.sourceforge.net/ -- the home of FXSL
Resume: http://fxsl.sf.net/DNovatchev/Resume/Res.html
 
M

Mike Partridge

No, you guessed perfectly! Thanks so much for your help, and I'm sorry
that my description was difficult to fathom. I see what you're doing,
but can you clarify something? How is count(preceding-sibling::*)+1
different than position() in this case?
I have limited understanding of how to use axes, so please bear with
me. If there are multiple <report> elements that need different sets
of <detail-column>s in <report-set> (see example xml below), how can I
reference the detail-column data from the current report only? If the
xml structure was static I could back up through parent nodes, but I
don't know how many <break>s there are so I can't hardcode the xpath.
I have a feeling there is a relatively simple way to do this using the
ancestor axis, but I'm not sure how.
If I were to create a key as you defined it for the following example
xml, they would conflict correct? That is why I think using the
ancestor axis is the best way.

<report-set>
<report>
<detail-data>
<detail-column position="1" dsc="col1" sum_fg="0"/>
<detail-column position="2" dsc="col2" sum_fg="1"/>
<detail-column position="3" dsc="col3" sum_fg="1"/>
<detail-column position="4" dsc="col4" sum_fg="1"/>
<detail-column position="5" dsc="col5" sum_fg="1"/>
</detail-data>
<invoice inv_id="232243">
<break level="1">
<break level="2">
<break level="3">
...
</break>
</break>
</break>
</invoice>
</report>
<report>
<detail-data>
<detail-column position="1" dsc="name" sum_fg="0"/>
<detail-column position="2" dsc="description" sum_fg="0"/>
<detail-column position="3" dsc="amount" sum_fg="1"/>
</detail-data>
<invoice inv_id="232244">
<break level="1">
<break level="2">
...
</break>
</break>
</invoice>
</report>
</report-set>

Thanks again for your help!

Mike Partridge

Dimitre Novatchev said:
When I am in the <break> context (of which there can be any number), I
want to output a sum of each field based on the <detail-data> from the
top. I've tried to apply-templates on the
/report-set/report/detail-data/detail-column which can give me a
column for each <detail-column>, but I need to sum from the context
where the apply-templates was called. Is this possible? I've hacked a
way by passing my context position and break level and going back to
look for the break i want, but it's inefficient and hard to read, not
to mention ugly.

Does anyone have any ideas? Please tell me there's an easier way!

Mike Partridge..


I am not sure what you exactly want, but if I guess well, this will answer
your question.

This transformation:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:eek:utput method="text"/>
<xsl:strip-space elements="*"/>

<xsl:key name="kDetail" match="detail-column" use="@position"/>

<xsl:template match="row">
<xsl:value-of select="sum(field[key('kDetail',
count(preceding-sibling::*)+1)/@sum_fg = 1])"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>



when applied on your source.xml:
-- snip --

produces this output:

6834
19296
13
5213


In case my guess about the real meaning of your message was unsuccessful,
could you, please, describe it in a correct and unambiguous way?


Dimitre Novatchev.
FXSL developer, XML Insider,

http://fxsl.sourceforge.net/ -- the home of FXSL
Resume: http://fxsl.sf.net/DNovatchev/Resume/Res.html
 
D

Dimitre Novatchev

Mike Partridge said:
No, you guessed perfectly! Thanks so much for your help, and I'm sorry
that my description was difficult to fathom. I see what you're doing,
but can you clarify something? How is count(preceding-sibling::*)+1
different than position() in this case?

In this case using either of them will produce the same results.

I wanted somehow to express that there's no need for the "position"
attribute on field elements and even that one can do without a
position() function.

There are other scenarios (e.g. when position is not used within a
location step) , when position() will only return the position of the
current node in the current node-list -- this is *not* the same as
count(preceding-sibling::*)+1 and depends on the way the
xsl:apply-templates or the xsl:for-each were specified.

I have limited understanding of how to use axes, so please bear with
me. If there are multiple <report> elements that need different sets
of <detail-column>s in <report-set> (see example xml below), how can I
reference the detail-column data from the current report only? If the
xml structure was static I could back up through parent nodes, but I
don't know how many <break>s there are so I can't hardcode the xpath.
I have a feeling there is a relatively simple way to do this using the
ancestor axis, but I'm not sure how.
If I were to create a key as you defined it for the following example
xml, they would conflict correct? That is why I think using the
ancestor axis is the best way.

There's no problem -- just use:

ancestor::report[1]/detail-data


Dimitre Novatchev.
FXSL developer, XML Insider,

http://fxsl.sourceforge.net/ -- the home of FXSL
Resume: http://fxsl.sf.net/DNovatchev/Resume/Res.html
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top