用于获取满足特定条件的元素的 XSL 键 [英] XSL key to get elements that meet specific criteria

查看:32
本文介绍了用于获取满足特定条件的元素的 XSL 键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理表格条目元素,并希望获得通过以下测试的同一个表格中的所有前面的条目元素:

I am working with table entry elements and want to get all preceding entry elements in the same table that pass the following test:

parent::row/preceding-sibling::row/entry
  [@morerows >= count(parent::row/following-sibling::row
    [not(preceding-sibling::row/entry
      [generate-id() = $id])])]
  [count(preceding-sibling::entry
    [not(@morerows)]) + 1 = count(current()/preceding-sibling::entry) + 1]

XPath 给了我想要的结果,但速度太慢了......我想使用密钥但遇到问题.

The XPath gives me the desired result, but it is painfully slow..... I would like to use a key but am having problems.

我定义了一个键如下:

<xsl:key name="moreRowsEntry" match="entry[@morerows]" use="."/>

虽然该键确实检索了具有 morerows 属性的所有条目元素,但实际上我只需要它来检索同一个祖先表中的那些元素.同样,我不知道如何测试 morerows 值.我尝试过诸如:

While the key does retrieve all entry elements with the morerows attribute, I actually only need it to retrieve those within the same ancestor table. As well, I am at a loss as to how to test the morerows value. I have tried things such as :

<xsl:for-each select="key('moreRowsEntry', (@morerows >= count(parent::row/following-sibling::row[not(preceding-sibling::row)/entry[generate-id() = $id])])) 和 (count(preceding-sibling::entry[not(@morerows)]) + 1 = count(current()/preceding-sibling::entry)+ 1))">

我必须使用 XSL 1.0 来做到这一点.任何和所有的帮助表示赞赏.

I have to do this using XSL 1.0. Any and all help is appreciated.

一些进一步的信息:

我正在将 CALS 表转换为 OOXML.对于 CALS 表中我知道缺少单元格的行中的每个条目,我需要添加这些额外的单元格.对于这些条目元素,我有一个 $id,它是元素的 generate-id() 值.

I am converting a CALS table to OOXML. For each entry in the CALS table that is within a row in which I know there are cells missing, I need to add those additional cells. For these entry elements I have an $id that is the generate-id() value of the element.

然后我有来自上面的 XPath,它测试表的前几行 (parent::row/preceding-sibling::row/entry) 中具有更多行的任何条目元素大于或等于其自身与 ID 为 $id 的条目之间的行数的属性,并且位于应插入空单元格的正确位置(count(preceding-sibling::entry[not(@morerows)]) + 1 = count(current()/preceding-sibling::entry) + 1)

I then have the XPath from above, which tests that any entry elements in the preceding rows of the table (parent::row/preceding-sibling::row/entry) that have a morerows attribute that is greater than or equal to the number of rows between itself and the entry with the id of $id, and that are in the correct position in which the empty cell should be inserted (count(preceding-sibling::entry[not(@morerows)]) + 1 = count(current()/preceding-sibling::entry) + 1)

简化的样本输入:

<table>
    <tbody>
        <row>
            <entry morerows="2">A</entry>
            <entry morerows="1">B</entry>
            <entry>C</entry>
            <entry>D</entry>
        </row>
        <row>
            <entry>E</entry>
            <entry>F</entry>
        </row>
        <row>
            <entry>G</entry>
            <entry>H</entry>
            <entry>I</entry>
        </row>
        <row>
            <entry>J</entry>
            <entry>K</entry>
            <entry>L</entry>
            <entry>M</entry>
        </row>
    </tbody>
</table>

简化的示例输出:

<w:tbl>
    <w:tr>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>A</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>B</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>C</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>D</w:t>
                </w:r>
            </w:p>
        </w:tc>
    </w:tr>
    <w:tr>
        <w:tc>
            <w:tcPr>
                <w:vMerge/>
            </w:tcPr>
            <w:p/>
        </w:tc>
        <w:tc>
            <w:tcPr>
                <w:vMerge/>
            </w:tcPr>
            <w:p/>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>E</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>F</w:t>
                </w:r>
            </w:p>
        </w:tc>
    </w:tr>
    <w:tr>
        <w:tc>
            <w:tcPr>
                <w:vMerge/>
            </w:tcPr>
            <w:p/>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>G</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>H</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>I</w:t>
                </w:r>
            </w:p>
        </w:tc>
    </w:tr>
    <w:tr>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>J</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>K</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>L</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>M</w:t>
                </w:r>
            </w:p>
        </w:tc>
    </w:tr>
</w:tbl>

输入使用 morerows 属性来指定跨行.输出要求使用 元素为每个跨区单元插入实际单元.

The input uses the morerows attribute to specify spanned rows. The output requires that actual cells be inserted with the <w:vMerge/> element for each spanned cell.

另一个示例:

在此示例中,还必须考虑合并列(由 namest 和 nameend 属性指定):

In this sample, there are also merged columns (specified by the namest and nameend attributes) that must also be taken in to account:

<table>
    <tgroup cols="7">
        <colspec colname="col1"/>
        <colspec colname="col2"/>
        <colspec colname="col3"/>
        <colspec colname="col4"/>
        <colspec colname="col5"/>
        <colspec colname="col6"/>
        <colspec colname="col7"/>
        <tbody>
            <row>
                <entry morerows="5">A</entry>
                <entry morerows="1">B</entry>
                <entry morerows="1">C</entry>
                <entry>D</entry>
                <entry>E</entry>
                <entry>F</entry>
                <entry>G</entry>
            </row>
            <row>
                <entry>2D</entry>
                <entry>2E</entry>
                <entry>2F</entry>
                <entry>2G</entry>
            </row>
            <row>
                <entry morerows="1">3B</entry>
                <entry morerows="1">3C</entry>
                <entry>3D</entry>
                <entry>3E</entry>
                <entry>3F</entry>
                <entry>3G</entry>
            </row>
            <row>
                <entry>4D</entry>
                <entry>4E</entry>
                <entry>4F</entry>
                <entry>4G</entry>
            </row>
            <row>
                <entry morerows="1" nameend="col6" namest="col2">3G - 4G</entry>
                <entry morerows="1">5G</entry>
            </row>
        </tbody>
    </tgroup>
</table>

输出:

<w:tbl>
    <w:tr>
        <w:tc>
            <w:tcPr>
                <w:vMerge w:val="restart"/>
            </w:tcPr>
            <w:p>
                <w:r>
                    <w:t>A</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:tcPr>
                <w:vMerge w:val="restart"/>
            </w:tcPr>
            <w:p>
                <w:r>
                    <w:t>B</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:tcPr>
                <w:vMerge w:val="restart"/>
            </w:tcPr>
            <w:p>
                <w:r>
                    <w:t>C</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>D</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>E</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>F</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>G</w:t>
                </w:r>
            </w:p>
        </w:tc>
    </w:tr>
    <w:tr>
        <w:tc>
            <w:tcPr>
                <w:vMerge/>
            </w:tcPr>
            <w:p/>
        </w:tc>
        <w:tc>
            <w:tcPr>
                <w:vMerge/>
            </w:tcPr>
            <w:p/>
        </w:tc>
        <w:tc>
            <w:tcPr>
                <w:vMerge/>
            </w:tcPr>
            <w:p/>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>2D</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>2E</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>2F</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>2G</w:t>
                </w:r>
            </w:p>
        </w:tc>
    </w:tr>
    <w:tr>
        <w:tc>
            <w:tcPr>
                <w:vMerge/>
            </w:tcPr>
            <w:p/>
        </w:tc>
        <w:tc>
            <w:tcPr>
                <w:vMerge w:val="restart"/>
            </w:tcPr>
            <w:p>
                <w:r>
                    <w:t>3B</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:tcPr>
                <w:vMerge w:val="restart"/>
            </w:tcPr>
            <w:p>
                <w:r>
                    <w:t>3C</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>3D</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>3E</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>3F</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>3G</w:t>
                </w:r>
            </w:p>
        </w:tc>
    </w:tr>
    <w:tr>
        <w:tc>
            <w:tcPr>
                <w:vMerge/>
            </w:tcPr>
            <w:p/>
        </w:tc>
        <w:tc>
            <w:tcPr>
                <w:vMerge/>
            </w:tcPr>
            <w:p/>
        </w:tc>
        <w:tc>
            <w:tcPr>
                <w:vMerge/>
            </w:tcPr>
            <w:p/>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>4D</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>4E</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>4F</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>4G</w:t>
                </w:r>
            </w:p>
        </w:tc>
    </w:tr>
    <w:tr>
        <w:tc>
            <w:tcPr>
                <w:vMerge/>
            </w:tcPr>
            <w:p/>
        </w:tc>
        <w:tc>
            <w:tcPr>
                <w:gridSpan w:val="5"/>
            </w:tcPr>
            <w:p>
                <w:r>
                    <w:t>3G - 4G</w:t>
                </w:r>
            </w:p>
        </w:tc>
        <w:tc>
            <w:p>
                <w:r>
                    <w:t>5G</w:t>
                </w:r>
            </w:p>
        </w:tc>
    </w:tr>
</w:tbl>

推荐答案

如果您的处理器可以做到 exslt:node-set 函数 或等效的函数,例如 由 msxml 提供 然后您可以使用尾递归模板在程序上对其进行攻击.丑陋,我知道,完全违背我们通常推荐的 XSLT,但在这种情况下,我认为有效地做到这一点的唯一方法是将信息从一行传递到下一行.假设表格的第一行的每一列总是有一个entry,那么这样的事情怎么样:

If your processor can do the exslt:node-set function or an equivalent such as that provided by msxml then you could attack this procedurally, using a tail-recursive template. Ugly, I know, and completely against what we usually recommend for XSLT, but in this case I think the only way to do this efficiently is to pass information from one row to the next. Assuming that the first row of the table will always have an entry for every column, then how about something like this:

<xsl:template match="tbody">
  <w:tbl>
    <xsl:apply-templates select="row[1]">
      <xsl:with-param name="rowSpec">
        <!-- build the row info structure assuming that the first row has
             the right number of entry elements.  Nothing spans into the
             first row, so they all get @span=0 -->
        <xsl:for-each select="row[1]/entry">
          <r span="0" />
        </xsl:for-each>
      </xsl:with-param>
    </xsl:apply-templates>
  </w:tbl>
</xsl:template>

<xsl:template match="row">
  <xsl:param name="rowSpec" />
  <xsl:variable name="theRow" select="." />

  <w:tr>
    <!-- build up the output for this row -->
    <xsl:for-each select="exsl:node-set($rowSpec)/r">
      <w:tc>
        <xsl:choose>
          <xsl:when test="@span = 0">
            <!-- this row has an entry for the column -->
            <xsl:apply-templates select="$theRow/entry[
               count(current()/preceding-sibling::r[@span = 0]) + 1]" />
          </xsl:when>
          <xsl:otherwise>
            <!-- this column spans from the previous row -->
            <w:tcPr>
              <w:vMerge/>
            </w:tcPr>
            <w:p/>
          </xsl:otherwise>
        </xsl:choose>
      </w:tc>
    </xsl:for-each>
  </w:tr>

  <!-- process the next row with recalculated spans -->
  <xsl:apply-templates select="following-sibling::row[1]">
    <xsl:with-param name="rowSpec">
      <xsl:for-each select="exsl:node-set($rowSpec)/r">
        <xsl:choose>
          <xsl:when test="@span = 0">
            <!-- we had an entry element for this column, use its @morerows
                 as the next span, or 0 if it doesn't have one -->
            <xsl:choose>
              <xsl:when test="$theRow/entry[
                 count(current()/preceding-sibling::r[@span = 0]) + 1]/@morerows">
                <r span="{$theRow/entry[
                 count(current()/preceding-sibling::r[@span = 0]) + 1]/@morerows}" />
              </xsl:when>
              <xsl:otherwise>
                <r span="0" />
              </xsl:otherwise>
            </xsl:choose>
          </xsl:when>
          <xsl:otherwise>
            <!-- we didn't have an entry for this column, it was a span from the
                 previous row - subtract 1 from the span when we pass on to
                 the next row -->
            <r span="{@span - 1}" />
          </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each>
    </xsl:with-param>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="entry">
  <w:p>
    <w:r>
      <w:t><xsl:value-of select="." /></w:t>
    </w:r>
  </w:p>
</xsl:template>

(哇,结果比我开始时预期的要复杂得多,但我已经测试过了,它似乎可以正常工作).这里的想法是我们构建一个结构,该结构对每列在处理该行时仍需要跨越的行数进行编码.所以对于第一行,我们将有

(Wow, that ended up much more complex than I expected when I started it, but I've tested it out and it seems to work correctly). The idea here is that we build a structure that encodes the number of rows that each column still needs to span over at the point where that row is processed. So for the first row we'll have

<r span="0"/>
<r span="0"/>
<r span="0"/>
<r span="0"/>

然后是第二个

<r span="2"/>
<r span="1"/>
<r span="0"/>
<r span="0"/>

第三个

<r span="1"/>
<r span="0"/>
<r span="0"/>
<r span="0"/>

等等.对于每一行,我们然后迭代这个结构而不是entry元素本身.

etc. For each row we then iterate over this structure rather than over the entry elements themselves.

现在你已经改变了问题,所以你需要考虑列跨度和行跨度的可能性,它变得更加混乱.由于我们致力于使用节点集函数,我会考虑 LarsH 暗示的两步方法,首先将跨越条目的列扩展为真正的 entry 元素(使用一些属性来标识它们),然后处理 XML 的扩展版本来代替原始版本.

now you've changed the question so you need to account for the possibility of column spans as well as row spans it gets much much messier. Since we're committed to using a node-set function, I would think about a two-step approach as hinted at by LarsH, where you first expand out the column spanning entries into real entry elements (with some attribute to identify them as such) and then process the expanded version of the XML in place of the original.

这篇关于用于获取满足特定条件的元素的 XSL 键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆