Общая подстановка по всему XML (XSLT) - PullRequest
0 голосов
/ 27 августа 2010

По сути, сейчас я запускаю XSLT, затем открываю результат в Visual Studio и выполняю поиск и замену одного слова - в этом примере я хочу изменить все экземпляры "bar" на " myBar». Можно предположить, что все экземпляры "bar" находятся в текстовых элементах:

<someElement>bar.whatever</someElement>

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

<someElement>myBar.whatever</someElement>

Но предостережение в том, что я также выполняю другие преобразования, такие как переименование или перемещение элемента. Можно ли как-нибудь объединить эти две операции (преобразование и поиск и замена) в один XSLT? Возможно ли это для нескольких операций поиска и замены?

Вся помощь приветствуется и спасибо заранее!

Редактировать : из комментариев

Я должен был указать, что Я ЕСМЬ действительно используя XSLT 2.0. я читаю эта статья и пытается выяснить, как бы я использовал replace ()

Ответы [ 3 ]

5 голосов
/ 28 августа 2010

XSLT 1.0 не имеет надежного текстового поиска и замены. Вы можете создать что-то, что использует contains, substring-before и substring-after, но вы должны использовать рекурсивный шаблон для обработки случая, когда строка, которую вы пытаетесь исправить, имеет несколько вхождений подстроки. *

Это работает при условии, что ваше преобразование, которое перемещает и переименовывает элементы, является вариантом преобразования идентичности:

<xsl:template match="text()">
  <xsl:call-template name="replace">
    <xsl:with-param name="text" select="."/>
  </xsl:call-template>
</xsl:template>

<xsl:template name="replace">
  <xsl:param name="text"/>
  <xsl:choose>
    <xsl:when test="contains($text, 'bar')">
      <xsl:call-template name="replace">
        <xsl:with-param name="text" select="concat(
                        substring-before($text, 'bar'), 
                        'myBar',
                        substring-after($text, 'bar'))"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$text"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Обратите внимание, что где бы вы ни копировали значение элемента, используя value-of, вам нужно использовать apply-templates; изменить это:

<xsl:template match="someElement">
   <renamedElement>
      <xsl:value-of select="."/>
   <renamedElement>
</xsl:template>

в это:

<xsl:template match="someElement">
   <renamedElement>
      <xsl:apply-templates select="text()"/>
   <renamedElement>
</xsl:template>

Делать несколько замен немного сложнее. Вы должны расширить шаблон replace, чтобы получить аргументы searchFor и replaceWith, что достаточно просто, а затем сделать это в шаблоне text():

<xsl:variable name="pass1">
   <xsl:call-template name="replace">
      <xsl:with-param name="text" select="."/>
      <xsl:with-param name="searchFor">bar</xsl:with-param>
      <xsl:with-param name="replaceWith">myBar</xsl:with-param>
   </xsl:call-template>
</xsl:variable>

<xsl:variable name="pass2">
   <xsl:call-template name="replace">
      <xsl:with-param name="text" select="."/>
      <xsl:with-param name="searchFor">bar</xsl:with-param>
      <xsl:with-param name="replaceWith">myBar</xsl:with-param>
   </xsl:call-template>
</xsl:variable>

<xsl:value-of select="$pass2"/>

В XSLT 2.0, который поддерживает использование регулярных выражений на текстовых узлах, это намного проще. Вы по-прежнему создаете шаблон, который соответствует text(), но он просто вызывает replace. См. эту статью для получения дополнительной информации, если вам посчастливилось использовать XSLT 2.0.

1 голос
/ 27 августа 2010

РЕДАКТИРОВАТЬ : Теперь выяснилось, что ОП требует, чтобы каждое вхождение 'bar' заменялось на 'myBar', эта таблица стилей XSLT 1.0:

<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="text">
        <xsl:param name="pString" select="."/>
        <xsl:choose>
            <xsl:when test="contains($pString,'bar')">
                <xsl:value-of 
                select="concat(substring-before($pString,'bar'),'myBar')"/>
                <xsl:call-template name="text">
                    <xsl:with-param name="pString" 
                    select="substring-after($pString,'bar')"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$pString"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

С вводом:

<someElement>barbarian</someElement>

Вывод:

<someElement>myBarmyBarian</someElement>

Теперь таблица стилей XSLT 2.0:

<xsl:stylesheet version="2.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()">
        <xsl:value-of select="replace(.,'bar','myBar')"/>
    </xsl:template>
</xsl:stylesheet>

Примечание : сопоставление шаблонов текстовых узлов.

0 голосов
/ 29 августа 2010

Вы можете использовать шаблон Identity Transform, предложенный alejandro, и заменить его на exslt str: replace

Если ваш процессор не поддерживает это, вы можете найти реализацию какШаблон XSLT на той же странице.

Чтобы включить exslt, просто используйте соответствующее пространство имен в своей таблице стилей, как описано здесь

Некоторые дополнительные указатели: Подробнее оpattern здесь : и здесь .

Использование только первого шаблона приведет к копированию источника в пункт назначения без изменений.Затем вы можете просто добавить дополнительные шаблоны для каждого элемента, который вы хотите сделать более конкретным форматированием, в вашем случае тот, который соответствует «text ()», я думаю, что он заменяет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...