使用XSLT删除基于属性的元素

使用XSLT删除基于属性的元素,xslt,Xslt,当属性出现在条目中时,我需要隐藏元素。当属性cols存在时,剩余的空条目应隐藏在同一行中。当属性morerows存在时,应删除同一列下一行中的条目 样本输入: <?xml version="1.0"?> <table> <tbody> <row> <entry cols="2">Row 1 Col 1</entry> <entry></entry> <entry></entry>

当属性出现在条目中时,我需要隐藏元素。当属性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>

第1行第1列
第1行第4列
第1行第5列
第2行第1列
第2行第2列
第2行第3列
第2行第5列
第3行第1列
第3行第2列
第3行第3列
第3行第5列
输出:

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

第1行第1列
第1行第4列
第1行第5列
第2行第1列
第2行第2列
第2行第3列
第2行第5列
第3行第1列
第3行第2列
第3行第3列
第3行第5列
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


我编写了一些代码,试图通过三个步骤实现转换:

  • 标记那些由于
    cols
    属性而要删除的
    entry
    元素
  • 标记那些由于
    morerows
    属性而要删除的
    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>
    
    
    第1行第1列
    第1行第4列
    第1行第5列
    第2行第1列
    第2行第2列
    第2行第3列
    第2行第5列
    第3行第1列
    第3行第2列
    第3行第3列
    第3行第5列
    
    我确实明白了

    <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>
    
    
    第1行第1列
    第1行第4列
    第1行第5列
    第2行第1列
    第2行第2列
    第2行第3列
    第2行第5列
    第3行第1列
    第3行第2列
    第3行第3列
    第3行第5列
    

    但是我认为需要更复杂的输入和输出示例来测试代码,所以请这样做并报告。我假设在每个
    元素的
    条目
    元素中没有超过一个
    更多行
    属性,我不确定该假设是否适用于您的输入要求。

    我编写了一些代码,试图通过三个步骤实现转换:

  • 标记那些由于
    cols
    属性而要删除的
    entry
    元素
  • 标记那些由于
    morerows
    属性而要删除的
    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>
    
    
    第1行第1列
    第1行第4列
    第1行第5列
    第2行第1列
    第2行第2列
    第2行第3列
    第2行第5列
    第3行第1列
    第3行第2列
    第3行第3列
    第3行第5列
    
    我确实明白了

    <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>
    
    
    第1行第1列
    第1行第4列
    第1行第5列
    第2行第1列
    第2行第2列
    第2行第3列
    第2行第5列
    第3行第1列
    第3行第2列
    第3行第3列
    第3行第5列
    

    但是我认为需要更复杂的输入和输出示例来测试代码,所以请这样做并报告。我假设每个
    元素的
    条目
    元素中没有超过一个
    多行
    属性,我不确定该假设是否适用于您的输入要求。

    是否
    @cols
    @morerows
    属性仅存在于第一个
    中,或者它们可能在任何地方?@ABach:感谢您的回复
    @cols
    @morerows
    可能出现在任何地方,并且可能包含您在代码中使用的任何值,这是否意味着您可以使用诸如Saxon 9或AltovaXML之类的XSLT 2.0处理器来解决这个问题?@MartinHonnen:我可以使用XSLT 2.0和Saxon 9he版本来处理
    @cols
    @morerows
    属性只存在于第一个
    中,或者它们可能在任何地方?@ABach:感谢您的回复
    @cols
    @morerows
    可能出现在任何地方,并且可能包含您在代码中使用的任何值,这是否意味着您可以使用诸如Saxon 9或AltovaXML之类的XSLT 2.0处理器来解决这个问题?@MartinHonnen:我可以使用XSLT 2.0和Saxon 9版本来回答您的问题,我将检查并更新回复延迟的状态道歉。我测试了您的代码,它在当前XML中运行良好。但是,当出现多个morerows属性时,我无法删除条目元素,正如您所说,我认为只要每个
    行有一个
    morerows
    属性的
    entry
    ,它就可以工作。但是,如果每个
    行可以有多个
    条目
    具有
    更多行
    属性,则需要进行更多的工作。对不起,我没有时间去解决和实施这个问题。也许其他人可以帮助你。谢谢你的努力和及时的帮助。我将尝试自己修改。