Xslt,Xpath组子节点由一对两个

时间:2014-06-08 20:42:02

标签: xslt xpath xslt-1.0

我有以下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是独一无二的,因为没有直接的书籍儿童在其上方或下方符合分组标准,因为中间还有另一个孩子。

同样,我不知道其他子节点是什么(在这种情况下是纸)所以我不能使用它们的名称,属性和内容来匹配。

1 个答案:

答案 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>