XSLT - XML - 使用xsl:for的每个组 [英] XSLT - XML - For-each-group with xsl:choose
问题描述
我有以下XML文件:
<report>
<page name="Simple MasterPage">
<table id="__bookmark_1">
<table-band band-type="BAND_HEADER">
<row>
<cell>
<label>OPTYPE</label>
</cell>
<cell>
<label>REPORTNUM</label>
</cell>
<cell>
<label>REPORTNAME</label>
</cell>
<cell>
<label>CREATIONDATE</label>
</cell>
<cell>
<label>PERSONNAME</label>
</cell>
<cell>
<label>PERSONID</label>
</cell>
<cell>
<label>NUMELEM</label>
</cell>
<cell>
<label>COUNTRY</label>
</cell>
<cell>
<label>NATIONALITY</label>
</cell>
<cell>
<label>IDTYPE</label>
</cell>
<cell>
<label>STREET</label>
</cell>
<cell>
<label>CITY</label>
</cell>
<cell>
<label>POSTCODE</label>
</cell>
<cell>
<label>BIRTHDATE</label>
</cell>
<cell>
<label>GENDER</label>
</cell>
<cell>
<label>ALTPERSONID</label>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>EI</data>
</cell>
<cell>
<data>1</data>
</cell>
<cell>
<data>firstReport</data>
</cell>
<cell>
<data>2017-01-31</data>
</cell>
<cell>
<data>Alex Jones</data>
</cell>
<cell>
<data>100001</data>
</cell>
<cell>
<data>1</data>
</cell>
<cell>
<data>Portugal</data>
</cell>
<cell>
<data>Portuguese</data>
</cell>
<cell>
<data>i1</data>
</cell>
<cell>
<data>Jones Street</data>
</cell>
<cell>
<data>Lisbon</data>
</cell>
<cell>
<data>2600</data>
</cell>
<cell>
<data>1997-02-04</data>
</cell>
<cell>
<data>M</data>
</cell>
<cell>
<data></data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>EU</data>
</cell>
<cell>
<data>1</data>
</cell>
<cell>
<data>firstReport</data>
</cell>
<cell>
<data>2017-01-31</data>
</cell>
<cell>
<data>Ana Maria</data>
</cell>
<cell>
<data>100002</data>
</cell>
<cell>
<data>2</data>
</cell>
<cell>
<data>Portugal</data>
</cell>
<cell>
<data>Portuguese</data>
</cell>
<cell>
<data>i2</data>
</cell>
<cell>
<data>Maria Street</data>
</cell>
<cell>
<data>Lisbon</data>
</cell>
<cell>
<data>2600</data>
</cell>
<cell>
<data>1997-02-06</data>
</cell>
<cell>
<data>F</data>
</cell>
<cell>
<data>alt1</data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>EU</data>
</cell>
<cell>
<data>1</data>
</cell>
<cell>
<data>firstReport</data>
</cell>
<cell>
<data>2017-01-31</data>
</cell>
<cell>
<data>Ana Maria</data>
</cell>
<cell>
<data>100002</data>
</cell>
<cell>
<data>3</data>
</cell>
<cell>
<data>Portugal</data>
</cell>
<cell>
<data>Portuguese</data>
</cell>
<cell>
<data>i2</data>
</cell>
<cell>
<data>Maria Street</data>
</cell>
<cell>
<data>Lisbon</data>
</cell>
<cell>
<data>2600</data>
</cell>
<cell>
<data>1997-02-06</data>
</cell>
<cell>
<data>F</data>
</cell>
<cell>
<data>alt1</data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>EU</data>
</cell>
<cell>
<data>1</data>
</cell>
<cell>
<data>firstReport</data>
</cell>
<cell>
<data>2017-01-31</data>
</cell>
<cell>
<data>Ana Maria</data>
</cell>
<cell>
<data>100002</data>
</cell>
<cell>
<data>4</data>
</cell>
<cell>
<data>Portugal</data>
</cell>
<cell>
<data>Portuguese</data>
</cell>
<cell>
<data>i2</data>
</cell>
<cell>
<data>Maria Street</data>
</cell>
<cell>
<data>Lisbon</data>
</cell>
<cell>
<data>2600</data>
</cell>
<cell>
<data>1997-02-06</data>
</cell>
<cell>
<data>F</data>
</cell>
<cell>
<data>alt1</data>
</cell>
</row>
</table-band>
<table-band band-type="BAND_DETAIL">
<row>
<cell>
<data>EI</data>
</cell>
<cell>
<data>1</data>
</cell>
<cell>
<data>firstReport</data>
</cell>
<cell>
<data>2017-01-31</data>
</cell>
<cell>
<data>Alex Jones</data>
</cell>
<cell>
<data>100002</data>
</cell>
<cell>
<data>5</data>
</cell>
<cell>
<data>Portugal</data>
</cell>
<cell>
<data>Portuguese</data>
</cell>
<cell>
<data>i1</data>
</cell>
<cell>
<data>Jones Street</data>
</cell>
<cell>
<data>Lisbon</data>
</cell>
<cell>
<data>2600</data>
</cell>
<cell>
<data>1997-02-04</data>
</cell>
<cell>
<data>M</data>
</cell>
<cell>
<data></data>
</cell>
</row>
</table-band>
</table>
</page>
</report>
这是我用来转换它的XSLT,用户@Parfait告诉我如何构建在一个非常相似的帖子上。如果OPTYPE是EU,那么输出将有另一个名为altPersonID的输出元素;然后idType将设置personInfo属性。
This is the XSLT I'm using to transform it, that user @Parfait teached me how to build on a very similar post. If OPTYPE is EU, then the output will have another output element called altPersonID; Then idType will set the personInfo attributes.
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="xml" omit-xml-declaration="no" indent="yes" encoding="utf-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/report/page">
<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" versao="1.0">
<reportData>
<xsl:call-template name="top_build-attrib">
<xsl:with-param name="label_val">REPORTNUM</xsl:with-param>
<xsl:with-param name="attrib_nm">reportNum</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="top_build-attrib">
<xsl:with-param name="label_val">REPORTNAME</xsl:with-param>
<xsl:with-param name="attrib_nm">reportName</xsl:with-param>
</xsl:call-template>
</reportData>
<people>
<xsl:apply-templates select="table"/>
</people>
</entry>
</xsl:template>
<xsl:template name="top_build-attrib">
<xsl:param name="label_val"/>
<xsl:param name="attrib_nm"/>
<xsl:variable name="row_num" select="count(table/table-band[1]/row/cell[label=$label_val]/preceding-sibling::*)+1"/>
<xsl:attribute name="{$attrib_nm}"><xsl:value-of select="table/table-band[2]/row/cell[position()=$row_num]/data"/></xsl:attribute>
</xsl:template>
<xsl:template name="build-attrib">
<xsl:param name="label_val"/>
<xsl:param name="attrib_nm"/>
<xsl:variable name="row_num" select="count(ancestor::table/table-band[1]/row/cell[label=$label_val]/preceding-sibling::*)+1"/>
<xsl:attribute name="{$attrib_nm}"><xsl:value-of select="row/cell[position()=$row_num]/data"/></xsl:attribute>
</xsl:template>
<xsl:template name="elem_value">
<xsl:param name="label_val"/>
<xsl:variable name="row_num" select="count(ancestor::table/table-band[1]/row/cell[label=$label_val]/preceding-sibling::*)+1"/>
<xsl:value-of select="row/cell[position()=$row_num]/data"/>
</xsl:template>
<xsl:template match="table">
<xsl:variable name="op_type">
<xsl:value-of select="table-band/row/cell[position()=1]/data"/>
</xsl:variable>
<xsl:variable name="id_type">
<xsl:value-of select="table-band/row/cell[position()=10]/data"/>
</xsl:variable>
<xsl:for-each-group select="table-band" group-by="row/cell[position()=
count(ancestor::table/table-band[1]/row/cell[label='PERSONNAME']/preceding-sibling::*)+1]/data">
<xsl:choose>
<xsl:when test="$op_type = 'EI'">
<xsl:choose>
<xsl:when test="$id_type = 'i1'">
<person>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">OPTYPE</xsl:with-param>
<xsl:with-param name="attrib_nm">opType</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">PERSONID</xsl:with-param>
<xsl:with-param name="attrib_nm">personID</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">PERSONNAME</xsl:with-param>
<xsl:with-param name="attrib_nm">personName</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">COUNTRY</xsl:with-param>
<xsl:with-param name="attrib_nm">country</xsl:with-param>
</xsl:call-template>
<personInfo><!--if person id type equals i1-->
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">IDTYPE</xsl:with-param>
<xsl:with-param name="attrib_nm">idType</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">BIRTHDATE</xsl:with-param>
<xsl:with-param name="attrib_nm">birthDate</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">GENDER</xsl:with-param>
<xsl:with-param name="attrib_nm">gender</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">NATIONALITY</xsl:with-param>
<xsl:with-param name="attrib_nm">nationality</xsl:with-param>
</xsl:call-template>
</personInfo>
<listOfElements>
<xsl:for-each-group select="current-group()" group-by="row/cell[position()=
count(ancestor::table/table-band[1]/row/cell[label='NUMELEM']/preceding-sibling::*)+1]">
<element>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">CREATIONDATE</xsl:with-param>
<xsl:with-param name="attrib_nm">creationDate</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">NUMELEM</xsl:with-param>
<xsl:with-param name="attrib_nm">numElem</xsl:with-param>
</xsl:call-template>
</element>
</xsl:for-each-group>
</listOfElements>
</person>
</xsl:when>
<xsl:otherwise><!--id type equals i2, differences in personInfo-->
<person>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">OPTYPE</xsl:with-param>
<xsl:with-param name="attrib_nm">opType</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">PERSONID</xsl:with-param>
<xsl:with-param name="attrib_nm">personID</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">PERSONNAME</xsl:with-param>
<xsl:with-param name="attrib_nm">personName</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">COUNTRY</xsl:with-param>
<xsl:with-param name="attrib_nm">country</xsl:with-param>
</xsl:call-template>
<personInfo><!--if person id type equals i2-->
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">IDTYPE</xsl:with-param>
<xsl:with-param name="attrib_nm">idType</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">CITY</xsl:with-param>
<xsl:with-param name="attrib_nm">city</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">POSTCODE</xsl:with-param>
<xsl:with-param name="attrib_nm">postCode</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">STREET</xsl:with-param>
<xsl:with-param name="attrib_nm">street</xsl:with-param>
</xsl:call-template>
</personInfo>
<listOfElements>
<xsl:for-each-group select="current-group()" group-by="row/cell[position()=
count(ancestor::table/table-band[1]/row/cell[label='NUMELEM']/preceding-sibling::*)+1]">
<element>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">CREATIONDATE</xsl:with-param>
<xsl:with-param name="attrib_nm">creationDate</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">NUMELEM</xsl:with-param>
<xsl:with-param name="attrib_nm">numElem</xsl:with-param>
</xsl:call-template>
</element>
</xsl:for-each-group>
</listOfElements>
</person>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise> <!--op type equals EU, difference in altPersonID-->
<xsl:choose>
<xsl:when test="$id_type = 'i1'">
<person>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">OPTYPE</xsl:with-param>
<xsl:with-param name="attrib_nm">opType</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">PERSONID</xsl:with-param>
<xsl:with-param name="attrib_nm">personID</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">PERSONNAME</xsl:with-param>
<xsl:with-param name="attrib_nm">personName</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">COUNTRY</xsl:with-param>
<xsl:with-param name="attrib_nm">country</xsl:with-param>
</xsl:call-template>
<personInfo><!--if person id type equals i1-->
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">IDTYPE</xsl:with-param>
<xsl:with-param name="attrib_nm">idType</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">BIRTHDATE</xsl:with-param>
<xsl:with-param name="attrib_nm">birthDate</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">GENDER</xsl:with-param>
<xsl:with-param name="attrib_nm">gender</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">NATIONALITY</xsl:with-param>
<xsl:with-param name="attrib_nm">nationality</xsl:with-param>
</xsl:call-template>
</personInfo>
<listOfElements>
<xsl:for-each-group select="current-group()" group-by="row/cell[position()=
count(ancestor::table/table-band[1]/row/cell[label='NUMELEM']/preceding-sibling::*)+1]">
<element>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">CREATIONDATE</xsl:with-param>
<xsl:with-param name="attrib_nm">creationDate</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">NUMELEM</xsl:with-param>
<xsl:with-param name="attrib_nm">numElem</xsl:with-param>
</xsl:call-template>
</element>
</xsl:for-each-group>
</listOfElements>
<altPersonID>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">ALTPERSONID</xsl:with-param>
<xsl:with-param name="attrib_nm">alternativeID</xsl:with-param>
</xsl:call-template>
</altPersonID>
</person>
</xsl:when>
<xsl:otherwise><!--id type equals i2-->
<person>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">OPTYPE</xsl:with-param>
<xsl:with-param name="attrib_nm">opType</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">PERSONID</xsl:with-param>
<xsl:with-param name="attrib_nm">personID</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">PERSONNAME</xsl:with-param>
<xsl:with-param name="attrib_nm">personName</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">COUNTRY</xsl:with-param>
<xsl:with-param name="attrib_nm">country</xsl:with-param>
</xsl:call-template>
<personInfo><!--if person id type equals i2-->
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">IDTYPE</xsl:with-param>
<xsl:with-param name="attrib_nm">idType</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">CITY</xsl:with-param>
<xsl:with-param name="attrib_nm">city</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">POSTCODE</xsl:with-param>
<xsl:with-param name="attrib_nm">postCode</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">STREET</xsl:with-param>
<xsl:with-param name="attrib_nm">street</xsl:with-param>
</xsl:call-template>
</personInfo>
<listOfElements>
<xsl:for-each-group select="current-group()" group-by="row/cell[position()=
count(ancestor::table/table-band[1]/row/cell[label='NUMELEM']/preceding-sibling::*)+1]">
<element>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">CREATIONDATE</xsl:with-param>
<xsl:with-param name="attrib_nm">creationDate</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">NUMELEM</xsl:with-param>
<xsl:with-param name="attrib_nm">numElem</xsl:with-param>
</xsl:call-template>
</element>
</xsl:for-each-group>
</listOfElements>
<altPersonID>
<xsl:call-template name="build-attrib">
<xsl:with-param name="label_val">ALTPERSONID</xsl:with-param>
<xsl:with-param name="attrib_nm">alternativeID</xsl:with-param>
</xsl:call-template>
</altPersonID>
</person>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
basically, if you see the XSLT FIDDLE below, you’ll see that it’s outputing always in the same way, whether is OPTYPE is EU or EI and IDTYPE is i1 or i2
basically, if you see the XSLT FIDDLE below, you'll see that it's outputing always in the same way, whether is OPTYPE is EU or EI and IDTYPE is i1 or i2
XSLTFIDDLE: https://xsltfiddle.liberty-development.net/3NzcBt9/4
XSLTFIDDLE: https://xsltfiddle.liberty-development.net/3NzcBt9/4
EDIT
Output(image link):https://i.gyazo.com/31b8a11deb3b0f4d5c90bb20c10f7d4e.png
Output(image link):https://i.gyazo.com/31b8a11deb3b0f4d5c90bb20c10f7d4e.png
推荐答案
It’s a bit hard to give a precise answer because you have not shown your expected output, but it looks like the problem is that you have declared the op_type
and id_type
variables before the xsl:for-each-group
It's a bit hard to give a precise answer because you have not shown your expected output, but it looks like the problem is that you have declared the op_type
and id_type
variables before the xsl:for-each-group
<xsl:template match="table">
<xsl:variable name="op_type">
<xsl:value-of select="table-band/row/cell[position()=1]/data"/>
</xsl:variable>
<xsl:variable name="id_type">
<xsl:value-of select="table-band/row/cell[position()=10]/data"/>
</xsl:variable>
<xsl:for-each-group select="table-band" group-by="row/cell[position()=
count(ancestor::table/table-band[1]/row/cell[label='PERSONNAME']/preceding-sibling::*)+1]/data">
<xsl:choose>
....
What this means is that (as you are using XSLT 3.0), that op_type
variable will contain the value of all \"optype\" cells concatenated into one string. You could see this if you did an xsl:value-of
after your declaration
What this means is that (as you are using XSLT 3.0), that op_type
variable will contain the value of all "optype" cells concatenated into one string. You could see this if you did an xsl:value-of
after your declaration
<xsl:value-of select="$op_type" />
This returns the following
This returns the following
EI EU EU EU EI
What you need to do move the declaration inside the xsl:for-each-group
so that it is selects the value for the first row in the group.
What you need to do move the declaration inside the xsl:for-each-group
so that it is selects the value for the first row in the group.
<xsl:template match="table">
<xsl:for-each-group select="table-band" group-by="row/cell[position()=
count(ancestor::table/table-band[1]/row/cell[label='PERSONNAME']/preceding-sibling::*)+1]/data">
<xsl:variable name="op_type" select="row/cell[position()=1]/data"/>
<xsl:variable name="id_type" select="row/cell[position()=10]/data" />
<xsl:choose>
...
这篇关于XSLT - XML - 使用xsl:for的每个组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!