从XML内容中删除不匹配的括号和不匹配的括号

时间:2012-05-02 16:57:36

标签: xslt-1.0

我看到了与Ruby等有关的问题。我没有看到任何可以涵盖这种情况的答案。

我正在使用XSLT转换XML文档。 我被迫使用XSLT 1.0,因为使用XSLT和XPATH的应用程序仍然是1.0。

你会使用正则表达式在XSL中嵌入Javascript函数吗?

我有像这样的xml代码:

<document>
<content name="PROD_MAJ_CLS_CD" type="text" vse-streams="2" u="20" action="cluster" weight="1">2</content>
<content name="PART_DESC_SHORT" type="text" vse-streams="2" u="22" action="cluster" weight="1">SCREW-ROCKER</content>
</document>

name =“PART_DESC_SHORT”的content属性可以在其中加上括号和括号

谢谢, 保罗

1 个答案:

答案 0 :(得分:0)

在您的示例中,括号的 none 匹配,并且所有都是打开的括号;对于这种情况,删除不匹配的括号和括号的任务相当于删除所有括号和括号。使用translate函数最容易做到这一点:

<xsl:value-of select="translate(.,'([','')"/>

如果您确实需要保留匹配的大括号并将a(b[c]d(e形式的输入转换为ab[c]de,那么在XSLT中执行此操作的最简单方法是使用递归命名模板,该模板具有两个参数:输入字符串和记录目前处理的材料的堆栈。 (堆栈可以只是由您选择的分隔符分隔的一系列字符串,您希望它们不会出现在输入中。由于您将输入显示为来自属性值,&amp;#x9;可能是安全的选择(除非数据生产者使用数字字符引用,否则它将从输入中标准化),但如果您愿意,可以使用|||never-use-this-string-in-a-part-description|||。)

在初始调用时,只传递输入字符串,并使堆栈默认为空。

在每次使用非空输入的调用中,模板从输入流中取出一个字符并使用它做正确的事情:

  • for“(”和“[”,将新字符串压入堆栈。
  • for“]”和“)”匹配堆栈顶部项目的第一个字符,弹出堆栈两次,连接项目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>