对XSLT有点麻烦..我想我可能会以错误的方式解决它... 尝试使用具有特殊1状态的项目的SKU显示客户名称... 然后客户有特殊的2项等,然后是第2部分(我还没有开始)没有状态的项目
所以对于这个XML文件,输出将是
Joe prod1 //special1
Joe prod3 //special2
Joe prod2 //no status
Joe prod4 //no status
Joe prod5 //no status
John Smith prod6 prod8 //special1
John Smith prod7 //no status
John Smith prod9 //no status
John Smith prod10 //no status
目前有点可行,但问题是如果没有special1或special2,我无法弄清楚如何让它不打印客户名称..
并且我不确定如何显示之后没有状态的那些 - 任何帮助都将非常感谢!
XML:
<customer>
<name>Joe</name>
<order>
<item>
<SKU>prod1</SKU>
<status>special1</status>
</item>
<item>
<SKU>prod2</SKU>
</item>
<item>
<SKU>prod3</SKU>
<status>special2</status>
</item>
<item>
<SKU>prod4</SKU>
</item>
<item>
<SKU>prod5</SKU>
</item>
</order>
</customer>
<customer
<name>John Smith</name>
<order>
<item>
<SKU>prod6</SKU>
<status>special1</status>
</item>
<item>
<SKU>prod7</SKU>
</item>
<item>
<SKU>prod8</SKU>
<status>special1</status>
</item>
<item>
<SKU>prod9</SKU>
</item>
<item>
<SKU>prod10</SKU>
</item>
</order>
XSLT:
<!DOCTYPE xsl:stylesheet[ <!ENTITY nl "
"> ]>
<xsl:template match="customer">
<xsl:value-of select="name" /><xsl:apply-templates select="order/item[status='special1']" /><xsl:text>&nl;</xsl:text>
<xsl:value-of select="name" /><xsl:apply-templates select="order/item[status='special2']" /><xsl:text>&nl;</xsl:text>
</xsl:template>
<xsl:template match="item[status='special1']"><xsl:text> </xsl:text><xsl:value-of select="SKU" /></xsl:template>
<xsl:template match="item[status=special2']"><xsl:text> </xsl:text><xsl:value-of select="SKU" /></xsl:template>
<xsl:template match="text()"/>
答案 0 :(得分:0)
你最简单的选择只是一个xsl:if
<xsl:template match="customer">
<xsl:if test="order/item[status='special1']">
<xsl:value-of select="name" /><xsl:apply-templates select="order/item[status='special1']" /><xsl:text>&nl;</xsl:text>
</xsl:if>
<xsl:if test="order/item[status='special2']">
<xsl:value-of select="name" /><xsl:apply-templates select="order/item[status='special2']" /><xsl:text>&nl;</xsl:text>
</xsl:if>
</xsl:template>
答案 1 :(得分:0)
我假设您不知道先验的不同状态。因此,如果您不希望XML可维护(无需在每次添加其他状态时更改它),您可以使用以下解决方案:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<!-- Use the following key for grouping -->
<xsl:key name="status-key"
match="item"
use="status" />
<!-- Cache the following operation to avoid doing it several times in the future.
You can improve performance by changing // to a fixed path in your XML where
all the items are (e.g. /customers/customer/order/item) -->
<xsl:variable name="item-group"
select="//item[generate-id(.) = generate-id(key('status-key', status)[1])]" />
<xsl:template match="customer">
<!-- Obtain the following values before losing the current context -->
<xsl:variable name="current-id" select="generate-id(.)" />
<xsl:variable name="current-name" select="name" />
<!-- Display the products with a status defined -->
<xsl:for-each select="$item-group">
<!-- Obtain list of status for this costumer -->
<xsl:variable name="customer-status"
select="key('status-key', status)[generate-id(../..) = $current-id]" />
<!-- Print the status information if the costumer has at least one status -->
<xsl:if test="$customer-status">
<!-- Display the name of the costumer -->
<xsl:value-of select="$current-name" />
<!-- Group the product by status -->
<xsl:for-each select="$customer-status">
<xsl:value-of select="concat(' ', SKU)" />
</xsl:for-each>
<!-- Output the status -->
<xsl:value-of select="concat(' //', status, '
')" />
</xsl:if>
</xsl:for-each>
<!-- Display the prodcuts without status -->
<xsl:for-each select="order/item[not(status)]">
<xsl:value-of select="concat($current-name, ' ', SKU, ' //no-status
')" />
</xsl:for-each>
</xsl:template>
<xsl:template match="text()" />
</xsl:stylesheet>
答案 2 :(得分:0)
这是“分组”问题的一个示例。您正尝试通过客户和状态的组合对项目进行分组。解决这个问题的方法因您使用的是XSLT 1.0还是XSLT 2.0而有所不同。在XSLT 1.0中,您将使用一种名为Muenchian Grouping的技术。首先,通过定义一个键来保存要分组的节点。在这种情况下,您按客户和项目
进行分组<xsl:key name="items" match="item" use="concat(generate-id(../..), '|', status)" />
然后,对于您匹配的每个客户元素,您将获得每个项的不同状态元素,如下所示:
<xsl:apply-templates select="order/item
[status != '']
[generate-id() = generate-id(key('items', concat(generate-id(../..), '|', status))[1])]" />
基本上,这样做是查看客户的每个项,并选择在为状态元素定义的键中首先出现的项。
然后,在匹配具有状态的项目的模板中,您可以获得具有相同状态的单个项目,如下所示:
<xsl:apply-templates select="key('items', concat(generate-id(../..), '|', status))/SKU" />
选择没有状态的项目要容易得多
<xsl:apply-templates select="order/item[not(status != '')]" />
这是完整的XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="items" match="item" use="concat(generate-id(../..), '|', status)" />
<xsl:template match="customer">
<xsl:apply-templates select="order/item[status != ''][generate-id() = generate-id(key('items', concat(generate-id(../..), '|', status))[1])]" />
<xsl:apply-templates select="order/item[not(status != '')]" />
</xsl:template>
<xsl:template match="item[status !='']">
<xsl:value-of select="../../name" />
<xsl:apply-templates select="key('items', concat(generate-id(../..), '|', status))/SKU" />
<xsl:value-of select="concat(' //', status, ' ')" />
</xsl:template>
<xsl:template match="item">
<xsl:value-of select="concat(../../name, ' ', SKU, ' // no status ')" />
</xsl:template>
<xsl:template match="SKU">
<xsl:value-of select="concat(' ', .)" />
</xsl:template>
</xsl:stylesheet>
当应用于XML时,输出以下内容:
Joe prod1 //special1
Joe prod3 //special2
Joe prod2 // no status
Joe prod4 // no status
Joe prod5 // no status
John Smith prod6 prod8 //special1
John Smith prod7 // no status
John Smith prod9 // no status
John Smith prod10 // no status
如果你使用的是XSLT2.0,它会变得有点简单,因为你可以让我们使用 xsl:for-each-group 来处理分组:
<xsl:for-each-group select="order/item[status != '']" group-by="status">
然后要使用该组获取项目,请使用当前组()功能
<xsl:apply-templates select="current-group()/SKU" />
这是完整的XSLT2.0样式表,它也应该输出相同的结果:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="customer">
<xsl:for-each-group select="order/item[status != '']" group-by="status">
<xsl:value-of select="../../name" />
<xsl:apply-templates select="current-group()/SKU" />
<xsl:value-of select="concat(' //', status, ' ')" />
</xsl:for-each-group>
<xsl:apply-templates select="order/item[not(status != '')]" />
</xsl:template>
<xsl:template match="item">
<xsl:value-of select="concat(../../name, ' ', SKU, ' // no status ')" />
</xsl:template>
<xsl:template match="SKU">
<xsl:value-of select="concat(' ', .)" />
</xsl:template>
</xsl:stylesheet>