使用XSLT删除基于属性的元素
当属性出现在条目中时,我需要隐藏元素。当属性cols存在时,剩余的空条目应隐藏在同一行中。当属性morerows存在时,应删除同一列下一行中的条目 样本输入:使用XSLT删除基于属性的元素,xslt,Xslt,当属性出现在条目中时,我需要隐藏元素。当属性cols存在时,剩余的空条目应隐藏在同一行中。当属性morerows存在时,应删除同一列下一行中的条目 样本输入: <?xml version="1.0"?> <table> <tbody> <row> <entry cols="2">Row 1 Col 1</entry> <entry></entry> <entry></entry>
<?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
,它就可以工作。但是,如果每个行可以有多个条目
具有更多行
属性,则需要进行更多的工作。对不起,我没有时间去解决和实施这个问题。也许其他人可以帮助你。谢谢你的努力和及时的帮助。我将尝试自己修改。