XSLT distinct value of the ancestor element - xslt

This is the input XML:
<?xml version = "1.0"?>
<?xml-stylesheet type = "text/xsl" href = "students.xsl"?>
<book>
<chapter label="Chapter 1">
<para>Text Text<link role="kwd" linkend="Gloss_1">Term 1</link> Text</para>
<para>Text Text Text<link role="kwd" linkend="Gloss_2">Term 2</link></para>
<section>
<title>Key Terms</title>
<itemizedlist mark="none">
<listitem><para><link role="kwd" linkend="Gloss_1">Term 1</link> Def 1</para></listitem>
<listitem><para><link role="kwd" linkend="Gloss_2">Term 2</link> Def 2</para></listitem>
</itemizedlist>
</section>
</chapter>
<chapter label="Chapter 2">
<para>Text Text<link role="kwd" linkend="Gloss_3">Term 3</link> Text</para>
<para>Text Text Text<link role="kwd" linkend="Gloss_1">Term 1</link></para>
<section>
<title>Key Terms</title>
<itemizedlist mark="none">
<listitem><para><link role="kwd" linkend="Gloss_1">Term 1</link> Def 3</para></listitem>
<listitem><para><link role="kwd" linkend="Gloss_3">Term 3</link> Def 1</para></listitem>
</itemizedlist>
</section>
</chapter>
<chapter label="Chapter 3">
<para>Text Text<link role="kwd" linkend="Gloss_4">Term 4</link> Text</para>
<para>Text Text Text<link role="kwd" linkend="Gloss_2">Term 2</link></para>
<para>Text Text Text<link role="kwd" linkend="Gloss_5">Term 5</link></para>
<section>
<title>Key Terms</title>
<itemizedlist mark="none">
<listitem><para><link role="kwd" linkend="Gloss_2">Term 2</link> Def 2</para></listitem>
<listitem><para><link role="kwd" linkend="Gloss_4">Term 4</link> Def 4</para></listitem>
<listitem><para><link role="kwd" linkend="Gloss_5">Term 5</link> Def 5</para></listitem>
</itemizedlist>
</section>
</chapter>
<glossary>
<glossentry xml:id="Gloss_1"><glossterm>Term 1</glossterm><glossdef>Def 1</glossdef></glossentry>
<glossentry xml:id="Gloss_2"><glossterm>Term 2</glossterm><glossdef>Def 2</glossdef></glossentry>
<glossentry xml:id="Gloss_3"><glossterm>Term 3</glossterm><glossdef>Def 3</glossdef></glossentry>
<glossentry xml:id="Gloss_4"><glossterm>Term 4</glossterm><glossdef>Def 4</glossdef></glossentry>
<glossentry xml:id="Gloss_5"><glossterm>Term 5</glossterm><glossdef>Def 5</glossdef></glossentry>
</glossary>
</book>
Output would be:
<?xml version="1.0" encoding="utf-8"?>
<glossary>
<row>
<col1>Chapter 1</col1>
<col1>Chapter 2</col1>
<col2>Term 1</col2>
</row>
<row>
<col1>Chapter 1</col1>
<col1>Chapter 3</col1>
<col2>Term 2</col2>
</row>
<row>
<col1>Chapter 2</col1>
<col2>Term 3</col2>
</row>
<row>
<col1>Chapter 3</col1>
<col2>Term 4</col2>
</row>
<row>
<col1>Chapter 3</col1>
<col2>Term 5</col2>
</row>
</glossary>
My code is:
<xsl:result-document href="out.xml">
<glossary>
<xsl:for-each select="book/glossary/glossentry">
<row>
<xsl:for-each select="key('num', #xml:id)">
<col1>
<xsl:value-of select="ancestor::chapter/#label"/>
</col1>
</xsl:for-each>
<col2><xsl:value-of select="glossterm"/></col2>
</row>
</xsl:for-each>
</glossary>
</xsl:result-document>
The glossary items are listed twice in the book - One at the end of each chapter and a consolidated items at the end. I would like to get the chapter number(s) for each glossary term listed at the end of the book. I tried various things but I am unable to get distinct value of the ancestor element. Can someone please help?

I think you could simply reverse your point-of-view:
<xsl:key name="chapter-by-link" match="chapter" use="descendant::link/#linkend" />
<xsl:template match="/">
<!-- other stuff -->
<glossary>
<xsl:for-each select="book/glossary/glossentry">
<row>
<xsl:for-each select="key('chapter-by-link', #xml:id)">
<col1>
<xsl:value-of select="#label"/>
</col1>
</xsl:for-each>
<col2>
<xsl:value-of select="glossterm"/>
</col2>
</row>
</xsl:for-each>
</glossary>
</xsl:template>

I suppose it suffices to select the ancestor::chapter/#label attributes as duplicates would be eliminated with any step selecting nodes so you would just change
<xsl:for-each select="key('num', #xml:id)">
<col1>
<xsl:value-of select="ancestor::chapter/#label"/>
</col1>
</xsl:for-each>
to
<xsl:for-each select="key('num', #xml:id)/ancestor::chapter/#label">
<col1>
<xsl:value-of select="."/>
</col1>
</xsl:for-each>
or perhaps organize the code into small templates to have cleaner code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output indent="yes"/>
<xsl:key name="ref" match="link[#role = 'kwd']" use="#linkend"/>
<xsl:template match="book">
<glossary>
<xsl:apply-templates select="glossary/glossentry"/>
</glossary>
</xsl:template>
<xsl:template match="glossentry">
<row>
<xsl:apply-templates select="key('ref', #xml:id)/ancestor::chapter/#label"/>
<col2>
<xsl:value-of select="glossterm"/>
</col2>
</row>
</xsl:template>
<xsl:template match="chapter/#label">
<col1>
<xsl:value-of select="."/>
</col1>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/jyH9rNv

Related

Using sum() to sum up values with nested foreach()

I need help in properly specifying the input parameter for sum(). I encountered sum()'s output to concatenate the values instead of summing up.
My goal is: To sum values of Column6 when Column2 is "invoice"
In the example below, I have 2000 and 1000 for Column6 whose Column is "invoice".
I'm expecting it to display 3000 for <TotalAmount>
<Root>
<DataArea>
<Row>... </Row>
<Row>... </Row>
<!-- and so on -->
<Row>
<Column1>29/03/19</Column1>
<Column2>cr note</Column2>
<Column3>092-213280101</Column3>
<Column4>1,474.98 </Column4>
<Column5>103.25 </Column5>
<Column6>2000 </Column6>
</Row>
<Row>
<Column1>29/03/19</Column1>
<Column2>invoice</Column2>
<Column3>092-213280101</Column3>
<Column4>1,474.98 </Column4>
<Column5>103.25 </Column5>
<Column6>2000 </Column6>
</Row>
<Row>
<Column1>11/06/19</Column1>
<Column2>invoice</Column2>
<Column3>123-123456789</Column3>
<Column4>100.50 </Column4>
<Column5>100.50 </Column5>
<Column6>1000</Column6>
</Row>
</DataArea>
</Root>
<xsl:for-each
select="Root/DataArea/Row">
<xsl:if ... >
<TransactionSummary>
<DebitSummary>
<TotalAmount>
<xsl:attribute name="currencyID"></xsl:attribute>
<xsl:for-each select="../Row">
<xsl:if test="(Column2 = 'invoice') and (position() > 9) ">
<xsl:value-of select="sum(../Column6)" />
</xsl:if>
</xsl:for-each>
</TotalAmount>
</DebitSummary>
</TransactionSummary>
</xsl:if>
</xsl:for-each>
I tried sum(Column6), didn't work. Output: 20001000
I tried sum(../Column6), didn't work. Output: 00
I tried sum(../Row/Column6), didn't work. Output: Cannot convert string "" to a double
I tried sum(Root/DataArea/Row/Column6), didn't work. Output: 00
I'd appreciate any help.
Thank you.
You don't need the inner xsl:for-each here, you can do it with a single xsl:value-of with the conditions in the select
<xsl:value-of select="sum(../Row[Column2 = 'invoice' and position() > 9]/Column6)" />
Or, in the context of your snippet....
<xsl:for-each select="Root/DataArea/Row">
<TransactionSummary>
<DebitSummary>
<TotalAmount currencyID="">
<xsl:value-of select="sum(../Row[Column2 = 'invoice' and position() > 9]/Column6)" />
</TotalAmount>
</DebitSummary>
</TransactionSummary>
</xsl:for-each>
It seems you want something like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<TransactionSummary>
<DebitSummary>
<TotalAmount currencyID="someId">
<xsl:value-of select="sum(/*/*/Row[Column2 = 'invoice']/Column6)"/>
</TotalAmount>
</DebitSummary>
</TransactionSummary>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<Root>
<DataArea>
<Row>... </Row>
<Row>... </Row>
<!-- and so on -->
<Row>
<Column1>29/03/19</Column1>
<Column2>cr note</Column2>
<Column3>092-213280101</Column3>
<Column4>1,474.98 </Column4>
<Column5>103.25 </Column5>
<Column6>2000 </Column6>
</Row>
<Row>
<Column1>29/03/19</Column1>
<Column2>invoice</Column2>
<Column3>092-213280101</Column3>
<Column4>1,474.98 </Column4>
<Column5>103.25 </Column5>
<Column6>2000 </Column6>
</Row>
<Row>
<Column1>11/06/19</Column1>
<Column2>invoice</Column2>
<Column3>123-123456789</Column3>
<Column4>100.50 </Column4>
<Column5>100.50 </Column5>
<Column6>1000</Column6>
</Row>
</DataArea>
</Root>
the wanted result is produced:
<TransactionSummary>
<DebitSummary>
<TotalAmount currencyID="someId">3000</TotalAmount>
</DebitSummary>
</TransactionSummary>

Compare a processing instruction and get the file name

I'm writing an XSLT in which I need to see if a value is in preprocessing instruction. In my XML, the preprocessing looks like below.
<?xpp MAIN;1;1;0;0;69;0;0?>
Sample XML
<root>
<?xpp MAIN;1;0;0;0;73;0;0?>
<preface role="guideline">
<title>title</title>
<section role="group">
<para>data</para>
</section>
<section role="group">
<title>
<?xpp lp;0.5p?>Licences</title>
<itemizedlist mark="bullet">
<listitem>
<para>itemdata</para>
</listitem>
</itemizedlist>
</section>
<section role="group">
<title>
<?xpp lp;0.5p?>Letters to the Editor</title>
<itemizedlist mark="bullet">
<listitem>
<para><?xpp MAIN;1;0;0;0;74;0;0?>item data</para>
</listitem>
</itemizedlist>
</section>
</preface>
</root>
Sample1 XML
<root>
<?xpp MAIN;1;0;0;0;83;0;0?>
<preface role="guideline">
<title>title</title>
<section role="group">
<para>data</para>
</section>
<section role="group">
<title>
<?xpp lp;0.5p?>Licences</title>
<itemizedlist mark="bullet">
<listitem>
<para>itemdata</para>
</listitem>
</itemizedlist>
</section>
<section role="group">
<title>
<?xpp lp;0.5p?>Letters to the Editor</title>
<itemizedlist mark="bullet">
<listitem>
<para><?xpp MAIN;1;0;0;0;84;0;0?>item data</para>
</listitem>
</itemizedlist>
</section>
</preface>
</root>
For the below XML, I need to do the task of going through files and checking for the data. The Above sample XML and Sample1 XML are the files that I've loop through.
<root>
<table frame="none" tabstyle="wrap4">
<tgroup cols="4">
<colspec colnum="1" colname="col1" colwidth="10*"/>
<colspec colnum="2" colname="COLSPEC0" colwidth="10.00*"/>
<colspec colnum="3" colname="col2" colwidth="275*"/>
<colspec colnum="4" colname="col3" colwidth="15*"/>
<tbody>
<row>
<entry colsep="0" rowsep="0">Text1</entry>
<entry colsep="0" rowsep="0"/>
<entry colsep="0" rowsep="0"/>
<entry colsep="0" rowsep="0" align="right">75</entry>
</row>
<row>
<entry colsep="0" rowsep="0">Text2</entry>
<entry colsep="0" rowsep="0"/>
<entry colsep="0" rowsep="0"/>
<entry colsep="0" rowsep="0" align="right">84</entry>
</row>
</tbody>
</tgroup>
</table>
</root>
Here first I'm trying to loop through all the files available, in each file, look for the preprocessing containing MAIN in it and then see if my value is present in that preprocessing instruction. Below is my XSLT block.
<xsl:template match="entry[#align='right']" mode="y">
<xsl:analyze-string select="." regex="([0-9]+)">
<xsl:matching-substring>
<xsl:variable name="prent" select="document(document('file:///C:\Users\userId\Desktop\Proview\AUS Journal\02FEB/title.xml')/entry/file/#name)/*[contains(//root/processing-instruction('xpp')[contains(.,'MAIN')],regex-group(1))]/substring-before(tokenize(document-uri(/), '/')[last()], '.')"/>
<xsl:variable name="cha">
<xsl:value-of select="$prent"/>
</xsl:variable>
<xsl:variable name="size">
<xsl:value-of select="string-length($cha)"/>
</xsl:variable>
<xsl:variable name="conct">
<xsl:value-of select="concat($cha,'/pg_',.)"/>
</xsl:variable>
<a href="{$conct}">
<xsl:value-of select="regex-group(1)"/>
</a>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
When I run this I get the below error.
XSLT 2.0 Debugging Error: Error: file:///C:/Users/userId/Desktop/Proview/AUS%20Journal/02FEB/XSLT/Journal.xsl:674: Wrong occurrence to match required sequence type - Details: - XPTY0004: The supplied sequence ('2' item(s)) has the wrong occurrence to match the sequence type xs:string ('zero or one').
please let me know how can I fix this and get job done.
Thanks
Try whether changing the step
*[contains(//root/processing-instruction('xpp')[contains(.,'MAIN')],regex-group(1))]
to
*[//root/processing-instruction('xpp')[contains(.,'MAIN')][contains(., regex-group(1))]]
fixes the problem.

XML to pipe-delimited - How to copy/duplicate data to different rows

I'm new to XSLT and trying to transform from XML to pipe-delimited format. The problem that I'm having is that in the output, each claim has to be duplicated for each service line.
Expected Output:
EP030315706890704|TESTSUBMITTER|FAMILY HEALTHCARE|1122334455|1|99214|179.00
EP030315706890704|TESTSUBMITTER|FAMILY HEALTHCARE|1122334455|2|2000F|0.00
EP030315706890705|TESTSUBMITTER2|FAMILY HEALTHCARE|1122334455|1|99214|179.00
EP030315706890705|TESTSUBMITTER2|FAMILY HEALTHCARE|1122334455|2|2000F|0.00
Input XML looks as follows:
<payloadContainer>
<afile>
<clm>
<hdr>
<corn>EP030315706890704</corn>
<idSend>112233445</idSend>
<nmSend>TESTSUBMITTER</nmSend>
</hdr>
<provBill>
<name>
<nmOrg>FAMILY HEALTHCARE</nmOrg>
</name>
<id T="XX" P="P">1122334455</id>
</provBill>
<serv S="1">
<numLine>1</numLine>
<prof>
<px L="S">
<cdPx T="HC">99214</cdPx>
</px>
<amtChrg>179.00</amtChrg>
</prof>
</serv>
<serv S="2">
<numLine>2</numLine>
<prof>
<px L="S">
<cdPx T="HC">2000F</cdPx>
</px>
<amtChrg>0.00</amtChrg>
</prof>
</serv>
</clm>
<clm>
<hdr>
<corn>EP030315706890705</corn>
<idSend>112233445</idSend>
<nmSend>TESTSUBMITTER2</nmSend>
</hdr>
<provBill>
<name>
<nmOrg>FAMILY HEALTHCARE</nmOrg>
</name>
<id T="XX" P="P">1122334455</id>
</provBill>
<serv S="1">
<numLine>1</numLine>
<prof>
<px L="S">
<cdPx T="HC">99214</cdPx>
</px>
<amtChrg>179.00</amtChrg>
</prof>
</serv>
<serv S="2">
<numLine>2</numLine>
<prof>
<px L="S">
<cdPx T="HC">2000F</cdPx>
</px>
<amtChrg>0.00</amtChrg>
</prof>
</serv>
</clm>
</afile>
</payloadContainer>
Desired output XML:
<Table>
<row>
.... All the fields represented here.
</row>
</Table>
Possible solution: https://www.dropbox.com/s/wzvtzw7ihtgxx9o/claimtoRedshift.xsl
This scenario creates two row's dynamically. However, I'm still stuck at how to duplicate for each service line.
I don't see the connection of the linked XSLT to the question presented here. AFAICT, the following stylesheet will return the expected pipe-delimited output:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/payloadContainer">
<xsl:for-each select="afile/clm">
<xsl:variable name="common">
<xsl:value-of select="hdr/corn"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="hdr/nmSend"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="provBill/name/nmOrg"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="provBill/id"/>
<xsl:text>|</xsl:text>
</xsl:variable>
<xsl:for-each select="serv">
<xsl:value-of select="$common"/>
<xsl:value-of select="numLine"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="prof/px/cdPx"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="prof/amtChrg"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Multiple records/elements grouped to create new structure

I searched and came close to finding a solution but that requires Stylesheet 2.0 and I'm stuck on 1.0.
This is the sample XML I have:
<root>
<row>A1: Apples</row>
<row>B1: Red</row>
<row>C1: Reference text</row>
<row>badly formatted text which belongs to row above</row>
<row>and here.</row>
<row>D1: ABC</row>
<row>E1: 123</row>
<row>A1: Oranges</row>
<row>B1: Purple</row>
<row>C1: More References</row>
<row>with no identifier</row>
<row>again and here.</row>
<row>D1: DEF</row>
<row>E1: 456</row>
.
.
I want it to look like:
<root>
<row>
<A1>Apples</A1>
<B1>Red</B1>
<C1>Reference text badly formatted text which belongs to row above and here.</C1>
<D1>ABC</D1>
<E1>123</E1>
</row>
<row>
<A1>Oranges</A1>
<B1>Purple</B1>
<C1>More Reference with no identifier again and here.</C1>
<D1>DEF</D1>
<E1>456</E1>
</row>
.
.
There is a pattern to this which I can convert using other utilities but quite hard with XSL 1.0.
There are headings within the elements that I can use and the reference text field is multi-line when it gets converted to XML, it creates its own row for each line but it's always in the same position between C1 and D1. The actual name of the elements, ie is not important.
The row should break up after E1. I think my example is straightforward but this transformation is not. I consider myself not even a beginner at XML/XSL. I am learning from scratch and then I get shifted to other projects and then have to come back to it again. TIA.
Update: Another case I ran into with slightly different structure but I want the result to be the same:
<root>
<row>
<Field>A1: Apples</Field>
</row>
<row>
<Field>B1: Red</Field>
</row>
<row>
<Field>C1: Reference text</Field>
</row>
<row>
<Field>badly formatted text which belongs to row above</Field>
</row>
<row>
<Field>and here.</Field>
</row>
<row>
<Field>D1: ABC</Field>
</row>
<row>
<Field>E1: 123</Field>
</row>
<row>
<Field>A1: Oranges</Field>
</row>
<row>
<Field>B1: Purple</Field>
</row>
<row>
<Field>C1: More References</Field>
</row>
<row>
<Field>with no identifier</Field>
</row>
<row>
<Field>again and here.</Field>
</row>
<row>
<Field>D1: DEF</Field>
</row>
<row>
<Field>E1: 456</Field>
</row>
I tried applying an identity transform but didn't seem to work:
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match ="row/Field">
<xsl:apply-templates/>
</xsl:template>
This looks kind of tricky, but I have a solution which seems to work. It allows for a variable number of rows after the C1 row (it wasn't clear whether this was always 2 rows or not).
The solution makes heavy use of the following-sibling axis, which is probably very inefficient, especially for a large input file.
You can test it out here.
<xsl:template match="/root">
<!-- Loop through every "A1" row -->
<xsl:for-each select="row[substring-before(text(), ':') = 'A1']">
<!-- Add a <row> tag -->
<xsl:element name="row">
<!-- Add each of the A1-E1 tags by finding the first following-sibling that matches before the colon -->
<xsl:apply-templates select="." />
<xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'B1'][1]" />
<xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'C1'][1]" />
<xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'D1'][1]" />
<xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'E1'][1]" />
</xsl:element>
</xsl:for-each>
</xsl:template>
<!-- Process each row -->
<xsl:template match="/root/row">
<!-- Create an element whose name is whatever is before the colon in the text -->
<xsl:element name="{substring-before(text(), ':')}">
<!-- Output everything after the colon -->
<xsl:value-of select="normalize-space(substring-after(text(), ':'))" />
<!-- Special treatment for the C1 node -->
<xsl:if test="substring-before(text(), ':') = 'C1'">
<!-- Count how many A1 nodes exist after this node -->
<xsl:variable name="remainingA1nodes" select="count(following-sibling::*[substring-before(text(), ':') = 'A1'])" />
<!-- Loop through all following-siblings that don't have a colon at position 3, and still have the same number of following A1 rows as this one does -->
<xsl:for-each select="following-sibling::*[substring(text(), 3, 1) != ':'][count(following-sibling::*[substring-before(text(), ':') = 'A1']) = $remainingA1nodes]">
<xsl:text> </xsl:text>
<xsl:value-of select="." />
</xsl:for-each>
</xsl:if>
</xsl:element>
</xsl:template>
Every record or group is 7 lines.
Then why not do it simply by the numbers:
XSLT 1.0
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/root">
<root>
<xsl:for-each select="row[position() mod 7 = 1]">
<row>
<xsl:apply-templates select=". | following-sibling::row[position() < 3] | following-sibling::row[4 < position() and position() < 7]"/>
</row>
</xsl:for-each>
</root>
</xsl:template>
<xsl:template match="row">
<xsl:element name="{substring-before(., ': ')}">
<xsl:value-of select="substring-after(., ': ')"/>
</xsl:element>
</xsl:template>
<xsl:template match="row[starts-with(., 'C1: ')]">
<C1>
<xsl:value-of select="substring-after(., 'C1: ')"/>
<xsl:for-each select="following-sibling::row[position() < 3]">
<xsl:text> </xsl:text>
<xsl:value-of select="."/>
</xsl:for-each>
</C1>
</xsl:template>
</xsl:stylesheet>

Change template so XSLT Outputs a sum instead of a list of values

I have an XSLT template that is working fine.
<xsl:template match="Row[contains(BenefitType, 'MyBenefit')]">
<value>
<xsl:value-of select="BenefitList/Row/Premium* 12" />
</value>
</xsl:template>
The output is
<value>100</value>
<value>110</value>
What I would prefer is if it would just output 220. So, basically in the template I would need to use some sort of variable or looping to do this and then output the final summed value?
XSLT 1 compliance is required.
The template is being used as follows:
<xsl:apply-templates select="Root/Row[contains(BenefitType, 'MyBenefit')]" />
For some reason, when I use the contains here it only sums the first structure that matches and not all of them. If The XML values parent wasn't dependent on having a sibling element that matched a specific value then a'sum' approach would work.
The direct solution to the problem was already mentioned in the comments, but assuming you really want to do the same with some variables, this might be interesting for you:
XML:
<Root>
<Row>
<BenefitType>MyBenefit</BenefitType>
<BenefitList>
<Premium>100</Premium>
</BenefitList>
</Row>
<Row>
<BenefitType>MyBenefit, OtherBenefit</BenefitType>
<BenefitList>
<Premium>100</Premium>
</BenefitList>
</Row>
<Row>
<BenefitType>OtherBenefit</BenefitType>
<BenefitList>
<Premium>1000</Premium>
</BenefitList>
</Row>
<Row>
<BenefitType>OtherBenefit</BenefitType>
<BenefitList>
<Premium>1000</Premium>
</BenefitList>
</Row>
</Root>
XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl">
<xsl:template match="/">
<total>
<xsl:variable name="valuesXml">
<values>
<xsl:apply-templates select="Root/Row[contains(BenefitType, 'MyBenefit')]" />
</values>
</xsl:variable>
<xsl:variable name="values" select="exsl:node-set($valuesXml)/values/value" />
<xsl:value-of select="sum($values)" />
</total>
</xsl:template>
<xsl:template match="Row[contains(BenefitType, 'MyBenefit')]">
<value>
<xsl:value-of select="BenefitList/Premium * 12" />
</value>
</xsl:template>
</xsl:stylesheet>
Here the same result set generated in your question is saved in another variable, which can then again be processed.