当我将XML结构更改为具有多个这样的好实体时,如何使工作成为here描述的解决方案:
<?xml version="1.0" encoding="ISO-8859-1"?>
<Work>
<Good id = "1">
<list num="1050" id = "2531" desc="List 1">
<part num="1">
<pos isKey="0" id="2532" pid="2531" desc="Part 1" />
<pos num="1.2." isKey="0" id="2554" pid="2532" desc="Position 1.2" />
<pos num="1.2.6." isKey="1" id="2591" pid="2554" desc="Position 1.2.6" />
</part>
</list>
<list num="1090" id = "3029" desc="List 2">
<part num="2">
<pos isKey="0" id="3033" pid="3029" desc="Category 2" />
<pos isKey="0" id="3040" pid="3033" desc="Part 9" />
<pos num="9.2." isKey="0" id="3333" pid="3040" desc="Position 9.2" />
<pos num="9.2.1." isKey="0" id="3334" pid="3333" desc="Position 9.2.1" />
<pos num="9.2.1.2" isKey="1" id="3339" pid="3334" desc="Position 9.2.1.2" />
</part>
</list>
</Good>
<Good id = "2">
<list num="1050" id = "2531" desc="List 3">
<part num="1">
<pos isKey="0" id="2532" pid="2531" desc="Part 1" />
<pos num="1.2." isKey="0" id="2554" pid="2532" desc="Position 1.2" />
<pos num="1.2.6." isKey="0" id="2591" pid="2554" desc="Position 1.2.6" />
<pos num="1.2.6.1." isKey="1" id="2592" pid="2591" desc="Position 1.2.6.1" />
</part>
</list>
</Good>
</Work>
我尝试为Work / Good实体创建for-each循环,但它没有帮助:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" />
<!-- key to look up any element with an id attribute based on the value of
that id -->
<xsl:key name="elementsByPid" match="*[@pid]" use="@pid" />
<xsl:template match="/">
<html>
<body>
<h2>Lists</h2>
<xsl:apply-templates select="Work/Goods" />
</body>
</html>
</xsl:template>
<xsl:template match="Work/Goods">
<xsl:for-each select="Work/Goods">
<xsl:value-of select="."/>
</xsl:for-each>
<xsl:apply-templates select="Work/Goods/list" />
</xsl:template>
<xsl:template match="Work/Goods/list">
<xsl:for-each select="Work/Goods/list">
<xsl:value-of select="."/>
</xsl:for-each>
<xsl:apply-templates select="." mode="table"/>
</xsl:template>
<xsl:template match="*" mode="table">
<xsl:variable name="shouldOutput">
<xsl:apply-templates select="." mode="shouldOutput" />
</xsl:variable>
<xsl:if test="string-length($shouldOutput)">
<table>
<xsl:apply-templates select="." />
</table>
</xsl:if>
</xsl:template>
<!-- the main recursive logic - first produce output for this row, then
process any of the children (in the id->pid chain) that need to be
output -->
<xsl:template match="*">
<xsl:apply-templates select="." mode="row" />
<xsl:for-each select="key('elementsByPid', @id)">
<xsl:variable name="shouldOutput">
<xsl:apply-templates select="." mode="shouldOutput" />
</xsl:variable>
<xsl:if test="string-length($shouldOutput)">
<xsl:apply-templates select="." />
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="*" mode="row">
<tr>
<td colspan="2"><xsl:value-of select="@desc" /></td>
</tr>
</xsl:template>
<!-- special case for pos elements with a @num - produce two columns -->
<xsl:template match="pos[@num]" mode="row">
<tr>
<td><xsl:value-of select="@num" /></td>
<td><xsl:value-of select="@desc" /></td>
</tr>
</xsl:template>
<!-- check whether this node should be output by checking whether it, or any
of its descendants in the id->pid tree, has @out=1. The template will
return an empty RTF for nodes that should not be output, and an RTF
containing a text node with one or more "1" characters for nodes that
should. -->
<xsl:template match="*[@out='1']" mode="shouldOutput">1</xsl:template>
<xsl:template match="*" mode="shouldOutput">
<xsl:apply-templates select="key('elementsByPid', @id)"
mode="shouldOutput"/>
</xsl:template>
</xsl:stylesheet>
enter code here
模板中没有允许此代码工作 我应该改变什么才能使其发挥作用?
答案 0 :(得分:2)
您不需要使用任何for-each
,只需删除两个模板
<xsl:template match="Work/Goods">
<xsl:template match="Work/Goods/list">
完全,并将根模板改为简单地说
<xsl:template match="/">
<html>
<body>
<h2>Lists</h2>
<xsl:apply-templates select="Work/Good/list" mode="table" />
</body>
</html>
</xsl:template>
不需要显式迭代,因为单个select
表达式将提取所有list
元素中的所有Good
元素(请注意,您的XML示例具有名为{{的元素)在Good
元素中添加{}}而不是Goods
。
答案 1 :(得分:1)
我不确定,这是否是您的意思,但我希望以下内容对您有用。我的建议是两次处理文件。一次使用step1.xsl
,其结果为step2.xsl
。在我的答案的最后给出了关于转换的内容的解释。
为输入文件指定上面提供的输入文件的形式,但将属性out="1"
添加到<part />
元素之一
<?xml version="1.0" encoding="ISO-8859-1"?>
<Work>
<Good id = "1">
<list num="1050" id = "2531" desc="List 1">
<part num="1">
<pos isKey="0" id="2532" pid="2531" desc="Part 1" />
<pos num="1.2." isKey="0" id="2554" pid="2532" desc="Position 1.2" />
<pos num="1.2.6." isKey="1" id="2591" pid="2554" desc="Position 1.2.6" />
</part>
</list>
<list num="1090" id = "3029" desc="List 2">
<part num="2">
<pos isKey="0" id="3033" pid="3029" desc="Category 2" />
<pos isKey="0" id="3040" pid="3033" desc="Part 9" />
<pos num="9.2." isKey="0" id="3333" pid="3040" desc="Position 9.2" />
<pos num="9.2.1." isKey="0" id="3334" pid="3333" desc="Position 9.2.1" out="1" />
<pos num="9.2.1.2" isKey="1" id="3339" pid="3334" desc="Position 9.2.1.2" />
</part>
</list>
</Good>
<Good id = "2">
<list num="1050" id = "2531" desc="List 3">
<part num="1">
<pos isKey="0" id="2532" pid="2531" desc="Part 1" />
<pos num="1.2." isKey="0" id="2554" pid="2532" desc="Position 1.2" />
<pos num="1.2.6." isKey="0" id="2591" pid="2554" desc="Position 1.2.6" />
<pos num="1.2.6.1." isKey="1" id="2592" pid="2591" desc="Position 1.2.6.1" />
</part>
</list>
</Good>
</Work>
以下转化step1.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" />
<xsl:strip-space elements="*" />
<xsl:key name="id" match="pos" use="@id" />
<xsl:key name="pid" match="pos" use="@pid" />
<xsl:template match="@*|node()">
<xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
</xsl:template>
<xsl:template match="pos[count(key('id', @pid)) = 0]">
<xsl:variable name="id" select="@id" />
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates select="ancestor::Good//pos[@pid=$id]" mode="nested" />
</xsl:copy>
</xsl:template>
<xsl:template match="pos" />
<xsl:template match="pos" mode="nested">
<xsl:variable name="id" select="@id" />
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates select="ancestor::Good//pos[@pid=$id]" mode="nested" />
</xsl:copy>
</xsl:template>
</xsl:transform>
产生以下输出
<?xml version="1.0"?>
<Work>
<Good id="1">
<list num="1050" id="2531" desc="List 1">
<part num="1">
<pos isKey="0" id="2532" pid="2531" desc="Part 1">
<pos num="1.2." isKey="0" id="2554" pid="2532" desc="Position 1.2">
<pos num="1.2.6." isKey="1" id="2591" pid="2554" desc="Position 1.2.6"/>
</pos>
</pos>
</part>
</list>
<list num="1090" id="3029" desc="List 2">
<part num="2">
<pos isKey="0" id="3033" pid="3029" desc="Category 2">
<pos isKey="0" id="3040" pid="3033" desc="Part 9">
<pos num="9.2." isKey="0" id="3333" pid="3040" desc="Position 9.2">
<pos num="9.2.1." isKey="0" id="3334" pid="3333" desc="Position 9.2.1" out="1">
<pos num="9.2.1.2" isKey="1" id="3339" pid="3334" desc="Position 9.2.1.2"/>
</pos>
</pos>
</pos>
</pos>
</part>
</list>
</Good>
<Good id="2">
<list num="1050" id="2531" desc="List 3">
<part num="1">
<pos isKey="0" id="2532" pid="2531" desc="Part 1">
<pos num="1.2." isKey="0" id="2554" pid="2532" desc="Position 1.2">
<pos num="1.2.6." isKey="0" id="2591" pid="2554" desc="Position 1.2.6">
<pos num="1.2.6.1." isKey="1" id="2592" pid="2591" desc="Position 1.2.6.1"/>
</pos>
</pos>
</pos>
</part>
</list>
</Good>
</Work>
作为以下转化的输入step2.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<xsl:apply-templates match="pos[@out=1]" />
</xsl:template>
<xsl:template match="pos[@out=1]">
<table>
<tr><td><xsl:value-of select="ancestor::list/@desc" /></td></tr>
<xsl:for-each select="ancestor-or-self::pos[count(ancestor::pos) < 2]">
<xsl:sort select="position()" order="descending" />
<tr><td><xsl:value-of select="@desc" /></td></tr>
</xsl:for-each>
<xsl:for-each select="ancestor-or-self::pos[count(ancestor::pos) >= 2]">
<tr>
<td><xsl:value-of select="@num" /></td>
<td><xsl:value-of select="@desc" /></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:transform>
产生的输出看起来像我想要的那样
<?xml version="1.0"?>
<table>
<tr>
<td>List 2</td>
</tr>
<tr>
<td>Part 9</td>
</tr>
<tr>
<td>Category 2</td>
</tr>
<tr>
<td>9.2.</td>
<td>Position 9.2</td>
</tr>
<tr>
<td>9.2.1.</td>
<td>Position 9.2.1</td>
</tr>
</table>
请澄清是否没有。
说明:第一个转换step1.xsl
根据pos
属性从@pid
元素的平面列表构建嵌套层次结构。这使得在第二轮中更容易通过父母链。
第二个转换step2.xsl
然后匹配应该生成输出的每个pos
元素,由其@out
属性指示,并写出您在ASCII中作为ASCII艺术起草的结构表原来的问题。
尚未完成的是在相同的情况下合并相同的表格。两个pos[@out=1]
元素包含在同一list
。
答案 2 :(得分:1)
问题在于@pid
不足以正确识别<pos>
元素,因为多个商品中可能会出现相同的@pid
。
这意味着您需要将每个@pid
与<Good>
中所属的<xsl:key>
相关联(然后,在每次使用密钥时)。这可以通过构建@pid
和封闭Good/@id
的唯一字符串来完成。
concat(@pid, '|', ancestor::Good/@id)
以下内容基本上是来自previous question的XSLT。我突出了这些变化。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" />
<xsl:key name="elementsByPid" match="*[@pid]" use="concat(@pid, '|', ancestor::Good/@id)" />
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ -->
<xsl:template match="/">
<html>
<body>
<h2>Lists</h2>
<xsl:apply-templates select="/Work/Good/list" mode="table" />
</body>
</html>
</xsl:template>
<xsl:template match="*" mode="table">
<xsl:variable name="shouldOutput">
<xsl:apply-templates select="." mode="shouldOutput" />
</xsl:variable>
<xsl:if test="string-length($shouldOutput)">
<table>
<xsl:apply-templates select="." />
</table>
</xsl:if>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates select="." mode="row" />
<xsl:for-each select="key('elementsByPid', concat(@id, '|', ancestor::Good/@id))">
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ -->
<xsl:variable name="shouldOutput">
<xsl:apply-templates select="." mode="shouldOutput" />
</xsl:variable>
<xsl:if test="string-length($shouldOutput)">
<xsl:apply-templates select="." />
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="*" mode="row">
<tr>
<td colspan="2"><xsl:value-of select="@description" /></td>
</tr>
</xsl:template>
<xsl:template match="pos[@num]" mode="row">
<tr>
<td class="num"><xsl:value-of select="@num" /></td>
<td><xsl:value-of select="@description" /></td>
</tr>
</xsl:template>
<xsl:template match="*[@out='1']" mode="shouldOutput">1</xsl:template>
<xsl:template match="*" mode="shouldOutput">
<xsl:apply-templates select="key('elementsByPid', concat(@id, '|', ancestor::Good/@id))" mode="shouldOutput"/>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ -->
</xsl:template>
</xsl:stylesheet>
另见http://www.xmlplayground.com/9iG5oz。
PS:由于您似乎在了解<xsl:apply-templates>
的工作原理方面存在问题,因此您可能会发现an older answer of mine explaining it有用。我还写了an answer that explains <xsl:key>
。