首页 文章

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

提问于
浏览
1

我有以下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)逻辑是静态的,并且需要在书籍数量方面更灵活 .

Result:

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,因为它需要遍历我不知道的所有子节点 .

非常感谢帮助 .

干杯

UPDATE

对不起,我认为我的解释足以解决主要问题,所以我可以自己解决剩下的问题 . 无论如何,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>

正如你所看到的,只要有一个可能的“候选人”可以分组,这些书就会被一对两个组合在一起 . Books5,Books8和Books15是独一无二的,因为没有直接的书籍儿童在其上方或下方符合分组的标准,因为其间有另一个孩子 .

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

1 回答

  • 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>
    

相关问题