我对XSLT有疑问。基本上,我从下面的xml中寻找状态为“有货”的书籍的上次交易的唯一交付方式(邮件,家庭等)。例如,在下面的示例中,将显示“邮件”和“商店提货”。有人可以帮我XSLT吗?预先感谢。
<BookCollection>
<Book>
<status>In Stock</status>
<name>The Hunt for Red October</name>
<OrderHistory>
<Order>
<transactionid>sssss</transactionid>
<date>2018-03-24</date>
<Delivery>Home</Delivery>
</Order>
<Order>
<transactionid>sssss</transactionid>
<date>2018-04-23</date>
<Delivery>Mail</Delivery>
</Order>
</Orderhistory>
</Book>
<Book>
<name>A case of need</name>
<status>Pending Stock</status>
<OrderHistory>
<Order>
<transactionid>sssss</transactionid>
<date>2018-08-24</date>
<Delivery>Home</Delivery>
</Order>
<Order>
<transactionid>sssss</transactionid>
<date>2018-02-23</date>
<Delivery>Store Pickup</Delivery>
</Order>
</Orderhistory>
</Book>
<Book>
<name>Sharp Objects</name>
<status>In Stock</status>
<OrderHistory>
<Order>
<transactionid>sssss</transactionid>
<date>2018-01-24</date>
<Delivery>Home</Delivery>
</Order>
<Order>
<transactionid>sssss</transactionid>
<date>2018-05-23</date>
<Delivery>Store Pickup</Delivery>
</Order>
</Orderhistory>
</Book>
<Book>
<name>Happy Doomsday</name>
<status>In Stock</status>
<OrderHistory>
<Order>
<transactionid>aaa</transactionid>
<date>2018-01-24</date>
<Delivery>Mail</Delivery>
</Order>
<Order>
<transactionid>bb</transactionid>
<date>2018-03-23</date>
<Delivery>Store Pickup</Delivery>
</Order>
</Orderhistory>
</Book>
.......
.........
</Book>
</BookCollection>
答案 0 :(得分:0)
如果支持sort
函数https://www.w3.org/TR/xpath-functions/#func-sort的高阶版本,则可以在纯XPath 3中实现:
distinct-values(
BookCollection/Book[status = 'In Stock']
!
sort(
OrderHistory/Order,
(),
function($order) { xs:date($order/date) }
)[last()]/Delivery
)
与Saxon 9.8 EE或PE或任何其他支持高阶功能的XSLT 3处理器一起使用的完整XSLT 3样式表将是
<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:template match="/">
<xsl:value-of
select="distinct-values(
BookCollection/Book[status = 'In Stock'] ! sort(OrderHistory/Order, (), function($order) { xs:date($order/date) })[last()]/Delivery
)"
separator=", "/>
</xsl:template>
</xsl:stylesheet>
在不支持sort
的高阶变体的XSLT 3处理器(如Saxon 9.8 HE)中,您需要将排序委托给自己的函数:
<xsl:template match="/">
<xsl:value-of
select="distinct-values(
BookCollection/Book[status = 'In Stock'] ! mf:sort(OrderHistory/Order)[last()]/Delivery
)"
separator=", "/>
</xsl:template>
<xsl:function name="mf:sort" as="element(Order)*">
<xsl:param name="orders" as="element(Order)*"/>
<xsl:perform-sort select="$orders">
<xsl:sort select="xs:date(date)"/>
</xsl:perform-sort>
</xsl:function>
答案 1 :(得分:0)
通常,如果要查找不同的项目,可以将其视为一个分组问题,但是仅需要从每个组中输出一个值。在XSLT 1.0中,您将使用一种称为Muenchian Grouping的技术,这意味着定义这样的键:
<xsl:key name="orders" match="Order" use="Delivery" />
但是,您要按日期获取最后一个订单会增加复杂性。可能最简单的选择是为每个Order
OrderHistory
个元素的变量
<xsl:variable name="Orders">
<xsl:for-each select="//Book[status = 'In Stock']/OrderHistory">
<xsl:for-each select="Order">
<xsl:sort select="date" order="descending" />
<xsl:if test="position() = 1">
<xsl:copy-of select="." />
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:variable>
但是,您需要使用扩展功能将此“结果树片段”转换为节点集,然后可以使用Muencjian分组技术。最像您的流程支持EXSLT,这意味着添加此命名空间
xmlns:exsl="http://exslt.org/common"
然后,要从变量中获取不同的值,请执行此操作...
<xsl:for-each select="exsl:node-set($Orders)/Order[generate-id() = generate-id(key('orders', Delivery)[1])]">
尝试使用此XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
version="1.0">
<xsl:output method="text" />
<xsl:key name="orders" match="Order" use="Delivery" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="Orders">
<xsl:for-each select="//Book[status = 'In Stock']/OrderHistory">
<xsl:for-each select="Order">
<xsl:sort select="date" order="descending" />
<xsl:if test="position() = 1">
<xsl:copy-of select="." />
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/">
<xsl:for-each select="exsl:node-set($Orders)/Order[generate-id() = generate-id(key('orders', Delivery)[1])]">
<xsl:if test="position() > 1">, </xsl:if>
<xsl:value-of select="Delivery" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
在http://xsltfiddle.liberty-development.net/3NzcBtu/2(使用Microsoft的XSLTCompiledTransform,即XSLT 1.0)上查看此操作。
但是理想情况下,如果只是为了防止Martin Honnen感到厌烦,您应该考虑升级到XSLT 3.0。