我在下面粘贴了我的XML和XSLT的精简版本。
我差不多得到了我需要的东西,但我似乎无法获得“2级'如果xml的排序如下。
前2个订单元素的Class属性为“No Class'”。如果我把这些元素放在最后那么转换就可以了。但是,xml是按以下顺序接收的,因此需要像这样工作。
xml的顺序似乎是问题,所以我想也许可以对xml进行排序并放入变量然后我可以转换变量的内容。是否可以在xslt
中执行此操作有人可以帮忙吗?
XML:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE EmailOrder
SYSTEM "http://orders.bbb.co.uk/xml/Xorder.DTD">
<?xml-stylesheet type='text/xsl' href='BBSORG6.XSL'?>
<EmailOrders>
<Order Key="COLGRE1-20140914-2345">
<Customer_Msg>Class sort</Customer_Msg>
<OrderLine>
<OrderKey>COLGRE1-20140914-2345</OrderKey>
<ProductKey>1001</ProductKey>
<Qty>1</Qty>
<Free>0</Free>
<Cost>12.99</Cost>
<VAT_rate>0</VAT_rate>
<Details>Friends Character Encyclopedia </Details>
<Class>No Class</Class>
<Bags>0</Bags>
<Section>Funfare</Section>
</OrderLine>
<OrderLine>
<OrderKey>COLGRE1-20140914-2345</OrderKey>
<ProductKey>1002</ProductKey>
<Qty>2</Qty>
<Free>0</Free>
<Cost>19.98</Cost>
<VAT_rate>0</VAT_rate>
<Details>Winnie’s Big Bad Robot</Details>
<Class>No Class</Class>
<Bags>0</Bags>
<Section>Funfare</Section>
</OrderLine>
<OrderLine>
<OrderKey>COLGRE1-20140914-2345</OrderKey>
<ProductKey>1012</ProductKey>
<Qty>1</Qty>
<Free>0</Free>
<Cost>6.50</Cost>
<VAT_rate>0</VAT_rate>
<Details>Snow</Details>
<Class>Class 1</Class>
<Bags>5</Bags>
<Section>Funfare</Section>
</OrderLine>
<OrderLine>
<OrderKey>COLGRE1-20140914-2345</OrderKey>
<ProductKey>1088</ProductKey>
<Qty>2</Qty>
<Free>0</Free>
<Cost>17.98</Cost>
<VAT_rate>0</VAT_rate>
<Details>Great Fairy Bake Off</Details>
<Class>Class 1</Class>
<Bags>5</Bags>
<Section>Funfare</Section>
</OrderLine>
<OrderLine>
<OrderKey>COLGRE1-20140914-2345</OrderKey>
<ProductKey>1123</ProductKey>
<Qty>1</Qty>
<Free>0</Free>
<Cost>3.99</Cost>
<VAT_rate>0</VAT_rate>
<Details>Space</Details>
<Class>Class 1</Class>
<Bags>5</Bags>
<Section>Funfare</Section>
</OrderLine>
<OrderLine>
<OrderKey>COLGRE1-20140914-2345</OrderKey>
<ProductKey>1001</ProductKey>
<Qty>2</Qty>
<Free>0</Free>
<Cost>25.98</Cost>
<VAT_rate>0</VAT_rate>
<Details>Friends Character Encyclopedia </Details>
<Class>Class 2</Class>
<Bags>4</Bags>
<Section>Funfare</Section>
</OrderLine>
<OrderLine>
<OrderKey>COLGRE1-20140914-2345</OrderKey>
<ProductKey>1002</ProductKey>
<Qty>1</Qty>
<Free>0</Free>
<Cost>9.99</Cost>
<VAT_rate>0</VAT_rate>
<Details>Winnie’s Big Bad Robot</Details>
<Class>Class 2</Class>
<Bags>4</Bags>
<Section>Funfare</Section>
</OrderLine>
<OrderLine>
<OrderKey>COLGRE1-20140914-2345</OrderKey>
<ProductKey>1012</ProductKey>
<Qty>1</Qty>
<Free>0</Free>
<Cost>6.50</Cost>
<VAT_rate>0</VAT_rate>
<Details>Snow</Details>
<Class>Class 2</Class>
<Bags>4</Bags>
<Section>Funfare</Section>
</OrderLine>
<OrderLine>
<OrderKey>COLGRE1-20140914-2345</OrderKey>
<ProductKey>1023</ProductKey>
<Qty>10</Qty>
<Free>0</Free>
<Cost>69.90</Cost>
<VAT_rate>0</VAT_rate>
<Details>The Witch with an Itch</Details>
<Class>Class 2</Class>
<Bags>4</Bags>
<Section>Funfare</Section>
</OrderLine>
<OrderLine>
<OrderKey>COLGRE1-20140914-2345</OrderKey>
<ProductKey>1333</ProductKey>
<Qty>2</Qty>
<Free>0</Free>
<Cost>19.98</Cost>
<VAT_rate>0</VAT_rate>
<Details>Scientriffic: Planet Earth</Details>
<Class>Class 2</Class>
<Bags>4</Bags>
<Section>Book Zone</Section>
</OrderLine>
</Order>
</EmailOrders>
XSLT:
<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:template match="/">
<xsl:apply-templates select="EmailOrders/Order"/>
</xsl:template>
<xsl:template match="Order">
<TABLE WIDTH="65%" BORDER="1" CELLPADDING="4"
bgcolor="yellow" align="center">
<TR ALIGN="left">
<TD>Customer message</TD>
<TD>
<xsl:value-of select="Customer_Msg"/>
</TD>
</TR>
</TABLE>
<BR/>
<BR/>
<TABLE WIDTH="100%" BORDER="1" CELLPADDING="4"
bgcolor="lightyellow" rules="cols" align="center">
<xsl:choose>
<xsl:when test="Customer_Msg = 'Class sort' ">
<THEAD>
<TH>Class</TH>
<TH>List</TH>
<TH>Paid</TH>
<TH>Free</TH>
<TH>No.</TH>
<TH>Title</TH>
<TH>Price</TH>
</THEAD>
<xsl:for-each select="OrderLine">
<xsl:sort select="Class"/>
<xsl:sort select="ProductKey"/>
<TR ALIGN="left">
<TD>
<xsl:value-of select="Class"/>
</TD>
<TD>
<xsl:value-of select="Section"/>
</TD>
<TD>
<xsl:value-of select="Qty"/>
</TD>
<TD>
<xsl:value-of select="Free"/>
</TD>
<TD>
<xsl:value-of select="ProductKey"/>
</TD>
<TD>
<xsl:value-of select="Details"/>
</TD>
<TD>
<xsl:value-of select="Cost"/>
</TD>
</TR>
<xsl:if test="Class != following::Class[1] or position() = last()">
<xsl:variable name="LastClass">
<xsl:value-of select="Class"/>
</xsl:variable>
<TR ALIGN="left" bgcolor="lightblue">
<TD>
<xsl:value-of select="$LastClass"/> Totals</TD>
<TD><xsl:value-of select="Bags"/> Bags</TD>
<TD>
<xsl:value-of select="sum(/EmailOrders
/Order/OrderLine
[Class=$LastClass]/Qty)"/>
</TD>
<TD>
<xsl:value-of select="sum(/EmailOrders
/Order/OrderLine
[Class=$LastClass]/Free)"/>
</TD>
<TD/>
<TD/>
<TD>
<xsl:value-of select="format-number(
sum(
/EmailOrders
/Order/OrderLine
[Class=$LastClass]/Cost),
'#####.##')"/>
</TD>
</TR>
</xsl:if>
</xsl:for-each>
<TR ALIGN="left" bgcolor="lightseagreen">
<TD>Order totals</TD>
<TD/>
<TD>
<xsl:value-of select="sum(/EmailOrders
/Order/OrderLine/Qty)"/>
</TD>
<TD>
<xsl:value-of select="sum(/EmailOrders
/Order/OrderLine/Free)"/>
</TD>
<TD/>
<TD/>
<TD>
<xsl:value-of select="format-number(sum(/EmailOrders
/Order/OrderLine/Cost),
'#####.##')"/>
</TD>
</TR>
</xsl:when>
<xsl:otherwise>
<THEAD>
<TH>List</TH>
<TH>Paid</TH>
<TH>Free</TH>
<TH>Ref</TH>
<TH>Title</TH>
<TH>Total</TH>
</THEAD>
<xsl:for-each select="OrderLine">
<xsl:sort select="ProductKey"/>
<TR ALIGN="left">
<TD>
<xsl:value-of select="Section"/>
</TD>
<TD>
<xsl:value-of select="Qty"/>
</TD>
<TD>
<xsl:value-of select="Free"/>
</TD>
<TD>
<xsl:value-of select="ProductKey"/>
</TD>
<TD>
<xsl:value-of select="Details"/>
</TD>
<TD>
<xsl:value-of select="Cost"/>
</TD>
</TR>
<xsl:if test="Section != following::Section[1]
or position() = last()">
<xsl:variable name="LastSection">
<xsl:value-of select="Section"/>
</xsl:variable>
<TR ALIGN="left" bgcolor="lightblue">
<TD>
<xsl:value-of select="Section"/> totals</TD>
<TD>
<xsl:value-of select="sum(/EmailOrders
/Order/OrderLine
[Section=$LastSection]/Qty)"/>
</TD>
<TD>
<xsl:value-of select="sum(/EmailOrders
/Order/OrderLine
[Section=$LastSection]/Free)"/>
</TD>
<TD/>
<TD/>
<TD>
<xsl:value-of select="format-number(
sum(/EmailOrders
/Order/OrderLine
[Section=$LastSection]
/Cost),
'#####.##')"/>
</TD>
</TR>
</xsl:if>
</xsl:for-each>
<TR ALIGN="left" bgcolor="lightseagreen">
<TD>Order totals</TD>
<TD>
<xsl:value-of select="sum(/EmailOrders
/Order/OrderLine/Qty)"/>
</TD>
<TD>
<xsl:value-of select="sum(/EmailOrders
/Order/OrderLine/Free)"/>
</TD>
<TD/>
<TD/>
<TD>
<xsl:value-of select="format-number(
sum(/EmailOrders
/Order/OrderLine
/Cost),
'#####.##')"/>
</TD>
</TR>
</xsl:otherwise>
</xsl:choose>
</TABLE>
<BR/>
<BR/>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:1)
问题归结为此行(或Section
元素的类似行。
<xsl:if test="Class != following::Class[1] or position() = last()">
此处following
轴的使用不依赖于Class
元素的排序顺序,而是原始文档中Class
元素的顺序。这就是您在重新订购文档时获得不同结果的原因。
如何解决?那么,你需要采取另一种方法。这实际上是分组问题的一个例子。有了这些问题,您可以使用的XSLT版本非常重要,因为在XSLT 2.0中,分组的处理方式与在XSLT 1.0中的处理方式不同。
您的样式表已指定version="2.0"
,但您也使用urn:schemas-microsoft-com:xslt
,Microsoft不喜欢XSLT 1.0。 (您可以使用XSLT 1.0处理器运行XSLT 2.0样式表,但它只会忽略它无法识别的命令)
假设使用XSLT 1.0,您将使用名为Muenchian Grouping
的技术为了这个答案的目的,专注于Class
元素,你可以像这样定义一个键:
<xsl:key name="OrderLine" match="OrderLine" use="Class" />
然后,您将获得不同的Class
元素,这些元素构成每个组的开头,如下所示:
<xsl:for-each select="OrderLine[generate-id() = generate-id(key('OrderLine', Class)[1])]">
<xsl:sort select="Class"/>
要获得组成该组的OrderLine
元素(即具有相同类的所有OrderLine
元素,您可以这样做:
<xsl:apply-templates select="key('OrderLine', Class)">
<xsl:sort select="ProductKey"/>
</xsl:apply-templates>
key
函数也可用于对类的总和求和。
试试这个(非常简化的)XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:key name="OrderLine" match="OrderLine" use="Class" />
<xsl:template match="/">
<xsl:apply-templates select="EmailOrders/Order"/>
</xsl:template>
<xsl:template match="Order">
<TABLE>
<THEAD>
<TH>Class</TH>
<TH>No.</TH>
<TH>Title</TH>
<TH>Price</TH>
</THEAD>
<xsl:for-each select="OrderLine[generate-id() = generate-id(key('OrderLine', Class)[1])]">
<xsl:sort select="Class"/>
<xsl:apply-templates select="key('OrderLine', Class)">
<xsl:sort select="ProductKey"/>
</xsl:apply-templates>
<TR>
<TD><xsl:value-of select="Class"/> Totals</TD>
<TD/>
<TD/>
<TD>
<xsl:value-of select="format-number(sum(key('OrderLine', Class)/Cost), '#####.##')"/>
</TD>
</TR>
</xsl:for-each>
<TR>
<TD>Totals</TD>
<TD/>
<TD/>
<TD>
<xsl:value-of select="format-number(sum(OrderLine/Cost), '#####.##')"/>
</TD>
</TR>
</TABLE>
</xsl:template>
<xsl:template match="OrderLine">
<TR ALIGN="left">
<TD><xsl:value-of select="Class"/></TD>
<TD><xsl:value-of select="ProductKey"/></TD>
<TD><xsl:value-of select="Details"/></TD>
<TD><xsl:value-of select="Cost"/></TD>
</TR>
</xsl:template>
</xsl:stylesheet>
现在,如果你可以使用XSLT 2.0,你可以使用xsl:for-each-group
命令,就像这样
<xsl:for-each-group select="OrderLine" group-by="Class">
然后,您将使用current-group
函数,而不是使用键来获取组中的项目。例如
<xsl:apply-templates select="current-group()">
<xsl:sort select="ProductKey"/>
</xsl:apply-templates>
同样在总和中
<xsl:value-of select="format-number(sum(current-group()/Cost), '#####.##')"/>