Xalan (XSLT) переводит метод перевода больше, чем должен - PullRequest
1 голос
/ 05 июля 2010

Кажется, у меня проблема с методом перевода Ксалана.У меня есть следующий код:

translate(translate(string(name),'<sup>',''),'</sup>','')

Это используется для удаления <sup> и </sup> из строки (имя).К сожалению, когда я это делаю, кажется, что s, u и p также удаляются из имен.Поэтому имена типа sony Braiva <sup>tm</sup> становятся ony bravia tm

Спасибо за вашу помощь заранее:)

Ответы [ 2 ]

5 голосов
/ 05 июля 2010

Поскольку вы сказали, что функция translate () успешно удаляет <sup> и </sup>, я предполагаю, что <sup> не является элементом в документе XML, но закодирован как текст.

Функция translate () определена для замены отдельных символов и, как правило, не подходит для замены строки , если длина строки больше 1.

В XSLT можно написать и использовать рекурсивный шаблон / функцию с общей заменой строк.

Программисты XSLT 2.0 могут использовать стандартную функцию XPath 2.0 replace ().

В вашем конкретном случае даже этого может быть достаточно:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="text()">
  <xsl:variable name="vPart1" select=
   "substring-before(., '&lt;sup>')"/>

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

  <xsl:variable name="vPart2" select=
   "substring-before(substring-after(., '&lt;sup>'),
                     '&lt;/sup>'
                     )"/>

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

  <xsl:variable name="vPart3" select=
   "substring-after(., '&lt;/sup>')"/>

  <xsl:value-of select="$vPart3"/>
 </xsl:template>
</xsl:stylesheet>

Когда это преобразование применяется к следующему документу XML :

<name>
 <![CDATA[sony Braiva <sup>tm</sup> xxx]]>
</name>

желаемый результат получается :

<name>
sony Braiva tm xxx
</name>

В качестве альтернативы приведено полнофункциональное рекурсивное шаблонное решение:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="text()">
  <xsl:variable name="vFirstReplacement">
      <xsl:call-template name="replace">
       <xsl:with-param name="pText" select="."/>
       <xsl:with-param name="pPattern"
         select="'&lt;sup>'"/>
       <xsl:with-param name="pReplacement" select="''"/>
      </xsl:call-template>
  </xsl:variable>

  <xsl:call-template name="replace">
   <xsl:with-param name="pText"
        select="$vFirstReplacement"/>
   <xsl:with-param name="pPattern"
     select="'&lt;/sup>'"/>
   <xsl:with-param name="pReplacement" select="''"/>
  </xsl:call-template>
 </xsl:template>

 <xsl:template name="replace">
  <xsl:param name="pText"/>
  <xsl:param name="pPattern"/>
  <xsl:param name="pReplacement"/>

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

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

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

Когда это преобразование применяется к этому документу XML :

<name>
 <![CDATA[sony Braiva <sup>tm</sup> xxx]]>
</name>

желаемый, правильный результат получается:

<name>
 sony Braiva tm xxx
</name>

Наконец, вот решение XSLT 2.0 :

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="text()">
  <xsl:value-of select=
   "replace(
            replace(., '&lt;sup>', ''),
            '&lt;/sup>',
            ''
            )
   "/>
 </xsl:template>
</xsl:stylesheet>
1 голос
/ 05 июля 2010

tl; dr версия: Не манипулируйте html или xml как строками, если вы можете избежать этого. Сделай это в XSLT.

Я предполагаю, что у вас есть элемент, который содержит что-то вроде

<name>Sony Braiva <sup>tm</sup></name>

Похоже, у вас есть разобранный XML-документ уже в XSLT. Затем вы поворачиваетесь и пытаетесь использовать манипуляции со строками, чтобы вытянуть некоторые теги. Это плохая идея; см. этот вопрос о соответствующих тегах. XSLT как раз для такого рода манипуляций, так что используйте его! (Если моё предположение неверно и что tm является сущностью или в разделе CDATA или где-то еще, я думаю, это другое).

Итак, во-первых. Если вы хотите удалить все теги без имени, оставив только текст , вы можете сделать

<xsl:value-of select="name" />

что даст:

Sony Braiva tm

Если, с другой стороны, вы хотите удалить все теги sup и их содержимое , вы сначала в другом месте определите шаблон, соответствующий sup (и сделайте то же самое со всем, что вы хотите удалить, например, теги сценария, теги img, что угодно):

<xsl:template match="sup" /> <!-- replace sup with nothing -->

И тогда вы можете подать

<xsl:apply-templates select="name" />

Если вы действительно хотите, вы можете даже сделать что-то вроде этого и заменить этот HTML хорошим символом Unicode. Было бы неплохо перевести это в другой режим и использовать этот режим для устранения всех других тегов.

<xsl:template match="sup" mode="mangle-name">
  <xsl:if test="'tm' = string(.)">
  &#8482;
  </xsl:if>
</xsl:template>

<!-- Later, somewhere else: -->
<xsl:apply-templates select="name" mode="mangle-name" />

Отказ от ответственности за все это: это стандартный XSLT (возможно, даже 1.0), но я пробовал его только в онлайн-саксонском парсере, а не в Xalan.

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