在您的示例中,没有一个括号匹配,并且都是开括号;在这种情况下,删除不匹配的括号和括号的任务相当于删除所有括号和括号。使用以下功能最容易做到这一点translate
:
<xsl:value-of select="translate(.,'([','')"/>
如果您确实需要保留匹配的大括号并将表单的输入a(b[c]d(e
转换为ab[c]de
,那么在 XSLT 中执行此操作的最简单方法是使用递归命名模板,该模板接受两个参数:输入字符串和记录到目前为止处理的材料的堆栈。(堆栈可以只是由您选择的分隔符分隔的字符串序列,您希望它不会出现在输入中。由于您将输入显示为来自属性值,&#x9;
因此可能是一个安全的选择(它将具有除非数据生成器为其使用数字字符引用,否则已从输入中标准化),但|||never-use-this-string-in-a-part-description|||
如果您愿意,可以使用。)
在初始调用中,您只传递输入字符串,并让堆栈默认为空。
在每次使用非空输入调用时,模板会从输入流中取出一个字符并用它做正确的事情:
- 对于“(”和“[”,将一个新字符串压入堆栈。
- 对于匹配栈顶项的第一个字符的“]”和“)”,弹出栈两次,连接第 2 项、第 1 项(旧的顶层项)和字符“]”或“)”,以及将串联压入堆栈。
- 对于不匹配的“]”和“)”,说明输入平衡不好,需要做点什么。(此处的代码删除了字符。)
- 对于任何其他字符,将其附加到堆栈的顶部项目。
因此,在任何给定时间,堆栈中的每个项目(除了底部项目)都以尚未匹配的左括号或括号开头。每次我们得到一个匹配,括号内的字符串被附加到堆栈上的下一个项目,从而减少堆栈大小。
当输入字符串用完并且堆栈中有多个项目时,需要剥离堆栈顶部项目上的前大括号并将顶部项目(减去大括号)附加到下一个项目。
一旦堆栈减少到一个项目,该项目将包含您想要的字符串。
这是在 XSLT 中:
<xsl:template name="paren-match-or-strip">
<xsl:param name="input"/>
<xsl:param name="stack"/>
<xsl:variable name="char"
select="substring($input,1,1)"/>
<xsl:variable name="stacktop"
select="substring-before($stack,$sep)"/>
<xsl:variable name="stackrest"
select="substring-after($stack,$sep)"/>
<xsl:choose>
<xsl:when test="not($input = '')">
<xsl:choose>
<xsl:when test="$char = '(' or $char = '['">
<!--* Push another potential-left-brace on the stack *-->
<xsl:call-template name="paren-match-or-strip">
<xsl:with-param name="input"
select="substring($input,2)"/>
<xsl:with-param name="stack"
select="concat(
$char,
$sep,
$stack
)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="($char = ']' and substring($stacktop,1,1) = '[')
or
($char = ')' and substring($stacktop,1,1) = '(')
">
<!--* Match the left brace at the top of the stack *-->
<xsl:variable name="stacktop2"
select="substring-before($stackrest,$sep)"/>
<xsl:variable name="stackrest2"
select="substring-after($stackrest,$sep)"/>
<xsl:call-template name="paren-match-or-strip">
<xsl:with-param name="input"
select="substring($input,2)"/>
<xsl:with-param name="stack"
select="concat(
$stacktop2,
$stacktop,
$char,
$sep,
$stackrest
)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="$char = ']' or $char = ')'">
<!--* Unmatched right brace, drop it silently *-->
<xsl:call-template name="paren-match-or-strip">
<xsl:with-param name="input"
select="substring($input,2)"/>
<xsl:with-param name="stack"
select="$stack"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="paren-match-or-strip">
<xsl:with-param name="input"
select="substring($input,2)"/>
<xsl:with-param name="stack"
select="concat(
$stacktop,
$char,
$sep,
$stackrest
)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$input = '' and contains($stackrest,$sep)">
<!--* Input is exhausted and at least one unmatched
* parenthesis is on the stack.
*-->
<xsl:variable name="stacktop2"
select="substring-before($stackrest,$sep)"/>
<xsl:variable name="stackrest2"
select="substring-after($stackrest,$sep)"/>
<xsl:call-template name="paren-match-or-strip">
<xsl:with-param name="input"
select="$input"/>
<xsl:with-param name="stack"
select="concat(
$stacktop2,
substring($stacktop,2),
$sep,
$stackrest2
)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!--* input is exhausted, stack only has one item *-->
<xsl:value-of select="substring-before($stack,$sep)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>