XSL:用xml标签替换某些字符

时间:2010-10-19 19:40:27

标签: xml xslt replace

这个有点棘手,我已经坚持了一段时间。我想做的是用标签代替括号'['(例如按钮,链接等),代替']'

<section>
    <title>Buttons</title>
    <orderedlist>
        <listitem>
            <para>Clicking on [Save] will attempt to save changes, then it navigates to <xref linkend="saved" xrefstyle="select: title"/>.</para>
        </listitem>
        <listitem>
            <para>Clicking on [Cancel] navigates to <xref linkend="noSave" xrefstyle="select: title"/>.</para>
        </listitem>
    </orderedlist>
</section>

要:

<section>
    <title>Buttons</title>
    <orderedlist>
        <listitem>
            <para>Clicking on <uicontrol>Save</uicontrol> will attempt to save changes, then it navigates to <xref linkend="saved" xrefstyle="select: title"/>.</para>
        </listitem>
        <listitem>
            <para>Clicking on <uicontrol>Cancel</uicontrol> navigates to <xref linkend="noSave" xrefstyle="select: title"/>.</para>
        </listitem>
    </orderedlist>
</section>

并且'['']'不一定总是在section.listitem.para

编辑:当括号中的某些字词时,我只需要替换[]。

3 个答案:

答案 0 :(得分:3)

对于嵌套括号没有嵌套uicontrol(需要解析平衡括号而不是平衡括号)。

此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>
 <xsl:template match="text()" name="replace" priority="1">
  <xsl:param name="pString" select="."/>
  <xsl:variable name="vMask" select="translate($pString,
                                                     translate($pString,
                                                               '[]',
                                                               ''),
                                                     '')"/>
  <xsl:choose>
   <xsl:when test="contains($vMask,'[]')">
    <xsl:call-template name="makeControl">
     <xsl:with-param name="pString" select="$pString"/>
     <xsl:with-param name="pMask"
                     select="substring-before($vMask,'[]')"/>
    </xsl:call-template>
   </xsl:when>
   <xsl:otherwise>
    <xsl:value-of select="$pString"/>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
 <xsl:template name="makeControl">
  <xsl:param name="pString"/>
  <xsl:param name="pMask"/>
  <xsl:choose>
   <xsl:when test="$pMask">
    <xsl:variable name="vMask" select="substring($pMask,1,1)"/>
    <xsl:value-of select="concat(
                             substring-before(
                                $pString,
                                $vMask),
                             $vMask)"/>
    <xsl:call-template name="makeControl">
     <xsl:with-param name="pString"
                     select="substring-after($pString,$vMask)"/>
     <xsl:with-param name="pMask" select="substring($pMask,2)"/>
    </xsl:call-template>
   </xsl:when>
   <xsl:otherwise>
    <xsl:value-of select="substring-before($pString,'[')"/>
    <uicontrol>
     <xsl:value-of select="substring-before(
                                             substring-after(
                                                $pString,
                                                '['),
                                             ']')"/>
    </uicontrol>
    <xsl:call-template name="replace">
     <xsl:with-param name="pString"
                                    select="substring-after($pString,']')"/>
    </xsl:call-template>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

输出:

<section>
 <title>Buttons</title>
 <orderedlist>
  <listitem>
   <para>Clicking on <uicontrol>Save</uicontrol> will attempt to save changes, then it navigates to <xref linkend="saved" xrefstyle="select: title"></xref>.</para>
  </listitem>
  <listitem>
   <para>Clicking on <uicontrol>Cancel</uicontrol> navigates to <xref linkend="noSave" xrefstyle="select: title"></xref>.</para>
  </listitem>
 </orderedlist>
</section>

有了这个输入:

<text>
This is an opening bracket [ ? [Yes] [No]
This is a closing bracket ] ? [Yes] [No]
</text>

输出:

<text>
This is an opening bracket [ ? <uicontrol>Yes</uicontrol> <uicontrol>No</uicontrol>
This is a closing bracket ] ? <uicontrol>Yes</uicontrol> <uicontrol>No</uicontrol>
</text>

注意:任何匹配\[[^\[\]]*\]的文字都会被包含在uicontrol元素中。

答案 1 :(得分:2)

您可以使用containssubstring-beforesubstring-after函数查找括号,然后根据需要插入元素而不是括号。

编辑 - 应该有效:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template name="insertElements">
        <xsl:param name="text" select="." />
        <xsl:choose>
            <xsl:when test="contains($text, '[')">
                <xsl:value-of select="substring-before($text, '[')"/>
                <xsl:variable name="after" select="substring-after($text, '[')" />
                <uicontrol>
                    <xsl:value-of select="substring-before($after, ']')"/>
                </uicontrol>
                <xsl:call-template name="insertElements">
                    <xsl:with-param name="text" select="substring-after($after, ']')" />
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$text"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:for-each select="node()">
                <xsl:choose>
                    <xsl:when test="self::text()">
                        <xsl:call-template name="insertElements" />
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:apply-templates select="." />
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

答案 2 :(得分:2)

此转化

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my" exclude-result-prefixes="my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <my:uicontrols>
  <control>[Save]</control>
  <control>[Cancel]</control>
 </my:uicontrols>

 <xsl:key name="kHasControls" match="text()"
  use="boolean(document('')/*/my:uicontrols/*[contains(current(), .)])"/>

 <xsl:variable name="vControls" select="document('')/*/my:uicontrols/*"/>

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

 <xsl:template match="text()[key('kHasControls', 'true')]">
  <xsl:choose>
   <xsl:when test="not($vControls[contains(current(),.)])">
     <xsl:copy-of select="."/>
   </xsl:when>
   <xsl:otherwise>
    <xsl:call-template name="createControl"/>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:template>

 <xsl:template name="createControl">
  <xsl:param name="pText" select="."/>

  <xsl:choose>
   <xsl:when test="not(contains($pText, '['))">
    <xsl:copy-of select="$pText"/>
   </xsl:when>
   <xsl:otherwise>
     <xsl:copy-of select="substring-before($pText, '[')"/>

     <xsl:variable name="vStartText" select=
     "concat('[', substring-after($pText, '['))"/>
     <xsl:variable name="vCtrl" select="$vControls[starts-with($vStartText,.)]"/>
     <xsl:choose>
      <xsl:when test="not($vCtrl)">
       <xsl:text>[</xsl:text>
       <xsl:call-template name="createControl">
         <xsl:with-param name="pText" select="substring($vStartText,1)"/>
       </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
       <uicontrol>
        <xsl:value-of select="translate($vCtrl,'[]','')"/>
       </uicontrol>

       <xsl:call-template name="createControl">
         <xsl:with-param name="pText" select="substring-after($vStartText, $vCtrl)"/>
       </xsl:call-template>
      </xsl:otherwise>
     </xsl:choose>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<section>
    <title>Buttons</title>
    <orderedlist>
        <listitem>
            <para>Clicking on [Save] will attempt to save changes, then it navigates to <xref linkend="saved" xrefstyle="select: title"/>.</para>
        </listitem>
        <listitem>
            <para>Clicking on [Cancel] navigates to <xref linkend="noSave" xrefstyle="select: title"/>.</para>
        </listitem>
    </orderedlist>
</section>

生成想要的正确结果

<section>
    <title>Buttons</title>
    <orderedlist>
        <listitem>
            <para>Clicking on <uicontrol>Save</uicontrol><xref linkend="saved" xrefstyle="select: title"/>.</para>
        </listitem>
        <listitem>
            <para>Clicking on <uicontrol>Cancel</uicontrol><xref linkend="noSave" xrefstyle="select: title"/>.</para>
        </listitem>
    </orderedlist>
</section>

请注意以下

  1. 此解决方案仅替换控件名称的受控列表。通过这种方式,我们可以防止意外错误,并且我们可以自由地使用"[Anything]"类型的字符串而不会出现任何问题(例如,我们希望显示一个着名的XPath表达式 - 根据定义,这样的表达式具有谓词:))

  2. 密钥的使用可确保提高效率,而不是扫描"["的每个文本节点。