XSL: замена некоторых символов тегами xml - PullRequest
6 голосов
/ 19 октября 2010

Это немного сложно, и я застрял на нем немного времени.Я хочу поставить теги вместо скобок '[' (например, для кнопок, ссылок и т. Д.) И вместо ']'

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

To:

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

3 голосов
/ 20 октября 2010

Без вложенных 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.

2 голосов
/ 20 октября 2010

Это преобразование :

<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. Использование ключей обеспечивает лучшую эффективность , чем сканирование каждого текстового узла на "[".

2 голосов
/ 19 октября 2010

Вы можете работать с функциями contains, substring-before и substring-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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...