1

当条目中存在属性时,我需要隐藏元素。当属性 cols 存在时,剩余的空条目应隐藏在同一行中。当存在属性 morerows 时,应删除同一列的下一行中存在的条目。

样本输入:

<?xml version="1.0"?>
<table>
<tbody>
<row>
<entry cols="2">Row 1 Col 1</entry>
<entry></entry>
<entry></entry>
<entry morerows="2">Row 1 Col 4</entry>
<entry>Row 1 Col 5</entry>
</row>
<row>
<entry>Row 2 Col 1</entry>
<entry>Row 2 Col 2</entry>
<entry>Row 2 Col 3</entry>
<entry></entry>
<entry>Row 2 Col 5</entry>
</row>
<row>
<entry>Row 3 Col 1</entry>
<entry>Row 3 Col 2</entry>
<entry>Row 3 Col 3</entry>
<entry></entry>
<entry>Row 3 Col 5</entry>
</row>
</tbody>
</table>

输出:

<?xml version="1.0"?>
<table>
<tbody>
<row>
<entry cols="2">Row 1 Col 1</entry>
<entry morerows="2">Row 1 Col 4</entry>
<entry>Row 1 Col 5</entry>
</row>
<row>
<entry>Row 2 Col 1</entry>
<entry>Row 2 Col 2</entry>
<entry>Row 2 Col 3</entry>
<entry>Row 2 Col 5</entry>
</row>
<row>
<entry>Row 3 Col 1</entry>
<entry>Row 3 Col 2</entry>
<entry>Row 3 Col 3</entry>
<entry>Row 3 Col 5</entry>
</row>
</tbody>
</table>

XSLT 试过:

<?xml version='1.0'?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:m="http://www.w3.org/1998/Math/MathML" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:mml="http://www.w3.org/1998/Math/MathML">
<xsl:output method="xml" encoding="UTF-8" indent="no"/>

<xsl:template match="@* | node()"><xsl:copy><xsl:apply-templates select="@* | node()"/></xsl:copy></xsl:template>

<xsl:template match="row">
<xsl:copy>
<xsl:for-each select="entry">
<xsl:if test="@cols"><xsl:variable name="span_cols" select="@cols+1"/></xsl:if>
<xsl:apply-templates select="following-sibling::*[$span_cols]"/>
</xsl:for-each>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>


<xsl:template match="entry">
<xsl:choose>
<xsl:when test="@cols">
<xsl:copy>
<xsl:variable name="current_colno" select="count(preceding-sibling::entry)+1"/>
<xsl:variable name="span_cols" select="@cols+1"/>
<xsl:attribute name="namest"><xsl:value-of select="$current_colno"/></xsl:attribute>
<xsl:attribute name="nameend"><xsl:value-of select="sum($span_cols,$current_colno)"/></xsl:attribute>
</xsl:copy>
</xsl:when>
<xsl:otherwise><xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy></xsl:otherwise>
</xsl:choose>
</xsl:template>

</xsl:stylesheet

>

4

1 回答 1

1

我编写了一些代码,尝试分三个步骤实现转换:

  1. 标记那些entrycols属性而被删除的元素
  2. 标记那些entrymorerows属性而被删除的元素
  3. 最后删除标记的entry元素

这是代码:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs">

<xsl:output indent="yes"/>

<xsl:template match="@* | node()" mode="#all">
  <xsl:copy>
    <xsl:apply-templates select="@* , node()" mode="#current"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="tbody">
  <xsl:copy>
    <xsl:variable name="cols-flagged-to-delete" as="element(tbody)">
      <xsl:copy>
        <xsl:apply-templates select="*" mode="flag-to-delete-col"/>
      </xsl:copy>
    </xsl:variable>
    <xsl:variable name="rows-flagged-to-delete" as="element(row)*">
      <xsl:apply-templates select="$cols-flagged-to-delete" mode="flag-to-delete-row"/>
    </xsl:variable>
    <xsl:apply-templates select="$rows-flagged-to-delete" mode="delete"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="tbody/row" mode="flag-to-delete-col">
  <xsl:copy>
    <xsl:for-each-group select="entry" group-starting-with="entry[@cols]">
      <xsl:choose>
        <xsl:when test="self::entry[@cols]">
          <xsl:variable name="cols" as="xs:integer" select="xs:integer(@cols)"/>
          <xsl:apply-templates select="."/>
          <xsl:apply-templates select="current-group()[not(node()) and position() gt 1 and position() le (1 + $cols)]"
             mode="flag-to-delete-col"/>
          <xsl:apply-templates select="current-group()[position() gt (1 + $cols)]"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:apply-templates select="current-group()"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each-group>
  </xsl:copy>
</xsl:template>

<xsl:template match="tbody/row/entry" mode="flag-to-delete-col flag-to-delete-row">
  <entry delete="true"/>
</xsl:template>

<xsl:template match="tbody" mode="flag-to-delete-row">
  <xsl:for-each-group select="row" group-starting-with="row[entry/@morerows]">
    <xsl:choose>
      <xsl:when test="self::row[entry/@morerows]">
        <xsl:variable name="pos" as="xs:integer" select="count(entry[@morerows]/preceding-sibling::entry) + 1"/>
        <xsl:variable name="n" as="xs:integer" select="xs:integer(entry/@morerows)"/>
        <xsl:apply-templates select="current-group()" mode="flag-to-delete-row">
          <xsl:with-param name="pos" select="$pos"/>
          <xsl:with-param name="n" select="$n"/>
        </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="current-group()"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each-group>
</xsl:template>

<xsl:template match="tbody/row" mode="flag-to-delete-row">
  <xsl:param name="pos"/>
  <xsl:param name="n"/>
  <xsl:copy>
    <xsl:choose>
      <xsl:when test="position() gt 1 and position() le (1 + $n)">
        <xsl:apply-templates select="entry[position() lt $pos]"/>
        <xsl:apply-templates select="entry[$pos]" mode="flag-to-delete-row"/>
        <xsl:apply-templates select="entry[position() gt $pos]"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="entry"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:copy>
</xsl:template>

<xsl:template match="row/entry[@delete = 'true']" mode="delete"/>

</xsl:stylesheet>

但是我只在您提供的小样本上进行了测试,所以当我使用 Saxon 9.5 进行转换时

<?xml version="1.0"?>
<table>
  <tbody>
    <row>
      <entry cols="2">Row 1 Col 1</entry>
      <entry></entry>
      <entry></entry>
      <entry morerows="2">Row 1 Col 4</entry>
      <entry>Row 1 Col 5</entry>
    </row>
    <row>
      <entry>Row 2 Col 1</entry>
      <entry>Row 2 Col 2</entry>
      <entry>Row 2 Col 3</entry>
      <entry></entry>
      <entry>Row 2 Col 5</entry>
    </row>
    <row>
      <entry>Row 3 Col 1</entry>
      <entry>Row 3 Col 2</entry>
      <entry>Row 3 Col 3</entry>
      <entry></entry>
      <entry>Row 3 Col 5</entry>
    </row>
  </tbody>
</table>

我确实得到

<table>
  <tbody>
      <row>
         <entry cols="2">Row 1 Col 1</entry>
         <entry morerows="2">Row 1 Col 4</entry>
         <entry>Row 1 Col 5</entry>
      </row>
      <row>
         <entry>Row 2 Col 1</entry>
         <entry>Row 2 Col 2</entry>
         <entry>Row 2 Col 3</entry>
         <entry>Row 2 Col 5</entry>
      </row>
      <row>
         <entry>Row 3 Col 1</entry>
         <entry>Row 3 Col 2</entry>
         <entry>Row 3 Col 3</entry>
         <entry>Row 3 Col 5</entry>
      </row>
   </tbody>
</table>

但是我认为需要更复杂的输入和输出样本来测试代码,所以请这样做并报告。而且我假设每个元素的元素内部不超过一个morerows属性,我不确定该假设是否适用于您的输入要求。entryrow

于 2013-05-31T18:08:43.923 回答