我有以下XML: (论文子可以是我现阶段不知道的节点的任何名称)
<catalog>
<Paper result="false">Paper1</Paper>
<Books result="true">Books1</Books>
<Books result="true">Books2</Books>
<Books result="true">Books3</Books>
<Books result="true">Books4</Books>
<Paper result="false">Paper2</Paper>
<Books result="false">Books5</Books>
<Paper result="false">Paper3</Paper>
<Books result="true">Books6</Books>
<Books result="true">Books7</Books>
<Books result="false">Books8</Books>
<Paper result="false">Paper4</Paper>
<Paper result="false">Paper5</Paper>
<Books result="true">Books9</Books>
<Books result="true">Books10</Books>
<Books result="true">Books11</Books>
<Books result="true">Books12</Books>
<Books result="true">Books13</Books>
<Books result="true">Books14</Books>
<Books result="false">Books15</Books>
</catalog>
我尝试将书籍分成两对。 在XML中,您可以看到所需Xpath的预期结果。
我的Xslt(1.0)到目前为止有点大而且没有真正起作用:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<table border="1">
<tr bgcolor="#9acd32">
<th>RESULT</th>
</tr>
<xsl:for-each select="catalog/child::*">
<tr>
<td>
<xsl:value-of select="."/> |
<xsl:value-of select="@result"/> =
<xsl:value-of select="( self::Books and following-sibling::*[1][self::Books] ) or
( self::Books and preceding-sibling::*[1][self::Books] and not( following-sibling::*[1][self::Books] ) and not( preceding-sibling::*[position()=2][self::Books] ) ) or
( self::Books and preceding-sibling::*[1][self::Books] and preceding-sibling::*[position()=1][self::Books] and preceding-sibling::*[position()=2][self::Books] and preceding-sibling::*[position()=3][self::Books] ) " />
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Xpath(1.0)逻辑是静态的,并且需要在书籍数量方面更加灵活。
结果:
Paper1 | false = false
Books1 | true = true
Books2 | true = true
Books3 | true = true
Books4 | true = true
Paper2 | false = false
Books5 | false = false
Paper3 | false = false
Books6 | true = true
Books7 | true = true
Books8 | false = false
Paper4 | false = false
Paper5 | false = false
Books9 | true = true
Books10 | true = true
Books11 | true = true
Books12 | true = true
Books13 | true = true
Books14 | true = true
Books15 | false = true
正如您所看到的,Books15的结果并不像预期的那样。
我可以扩展我的逻辑并添加7+书籍的案例,但这不是一个好方法。
另一种方法是计算前面的书籍并根据mod 2检查它们以查看数字是否均匀。因此,我知道当前的书籍是否可以与之前的书籍分组。但是,我很难在Books和其他子节点之间进行计数,因为我不知道名称和其他子节点的值。
任何人都有一个很好的方法来组合一对两个子节点吗?
当我在XSLT的有限环境中工作时,我无法使用密钥或者可以更改foreach,因为它需要迭代我不知道的所有子节点。
非常感谢帮助。
干杯
更新
对不起,我认为我的解释足以解决主要问题,所以我可以自己解决剩下的问题。无论如何,XML的所需最终结果输出应如下:
<table>
<tr><td>Paper1</td></tr>
</table>
<table>
<tr><td>Books1</td></tr>
<tr><td>Books2</td></tr>
</table>
<table>
<tr><td>Books3</td></tr>
<tr><td>Books4</td></tr>
</table>
<table>
<tr><td>Paper2</td></tr>
</table>
<table>
<tr><td>Books5</td></tr>
</table>
<table>
<tr><td>Paper3</td></tr>
</table>
<table>
<tr><td>Books6</td></tr>
<tr><td>Books7</td></tr>
</table>
<table>
<tr><td>Books8</td></tr>
</table>
<table>
<tr><td>Paper4</td></tr>
</table>
<table>
<tr><td>Books9</td></tr>
<tr><td>Books10</td></tr>
</table>
<table>
<tr><td>Books11</td></tr>
<tr><td>Books12</td></tr>
</table>
<table>
<tr><td>Books13</td></tr>
<tr><td>Books14</td></tr>
</table>
<table>
<tr><td>Books15</td></tr>
</table>
正如你所看到的,只要有可能的候选人和#34;这些书就会被一对两个组合在一起。与...分组。 Books5,Books8和Books15是独一无二的,因为没有直接的书籍儿童在其上方或下方符合分组标准,因为中间还有另一个孩子。
同样,我不知道其他子节点是什么(在这种情况下是纸)所以我不能使用它们的名称,属性和内容来匹配。
答案 0 :(得分:2)
这并不像我最初错误思考的那样微不足道。尝试:
XSLT 1.0
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:key name="grpOfBooks" match="Books" use="count(preceding-sibling::*[not(self::Books)])" />
<xsl:template match="/catalog">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="catalog/*[not(self::Books)]">
<table>
<tr>
<td><xsl:value-of select="."/></td>
</tr>
</table>
</xsl:template>
<xsl:template match="Books [count(. | key('grpOfBooks', count(preceding-sibling::*[not(self::Books)]))[1]) = 1]">
<xsl:for-each select="key('grpOfBooks',count(preceding-sibling::*[not(self::Books)]))[position() mod 2 = 1] ">
<table>
<tr>
<td><xsl:value-of select="."/></td>
<xsl:if test="following-sibling::*[1][self::Books]">
<td><xsl:value-of select="following-sibling::Books[1]"/></td>
</xsl:if>
</tr>
</table>
</xsl:for-each>
</xsl:template>
<xsl:template match="Books"/>
</xsl:stylesheet>
这是同样的事情,没有使用密钥实现(效率较低!):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/catalog">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="catalog/*[not(self::Books)]">
<table>
<tr>
<td><xsl:value-of select="."/></td>
</tr>
</table>
</xsl:template>
<xsl:template match="Books[not(preceding-sibling::*[1][self::Books])]">
<xsl:variable name="grp" select="count(preceding-sibling::*[not(self::Books)])" />
<xsl:for-each select="(. | following-sibling::Books) [count(preceding-sibling::*[not(self::Books)])=$grp] [position() mod 2 = 1] ">
<table>
<tr>
<td><xsl:value-of select="."/></td>
<xsl:if test="following-sibling::*[1][self::Books]">
<td><xsl:value-of select="following-sibling::Books[1]"/></td>
</xsl:if>
</tr>
</table>
</xsl:for-each>
</xsl:template>
<xsl:template match="Books"/>
</xsl:stylesheet>