Использование карты в XSL для расширения аббревиатур

Я видел аналогичный вопрос при создании карты.

Этот ответ имеет этот код:

<xsl:stylesheet version="1.0" 
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:template match="/">
    <xsl:variable name="map">
        <map>
            <entry key="key-1">value1</entry>
            <entry key="key-2">value2</entry>
            <entry key="key-3">value3</entry>
        </map>
    </xsl:variable>
    <output>
        <xsl:value-of select="msxsl:node-set($map)/map/entry[@key='key-1']"/>
    </output>
</xsl:template>

I would like to replace the output command to use a value in my XML to see if it is a key in the map and then replace it with the value.

Лучший способ сделать выбор для каждого на карте и сравнить с содержащимся?

Вот фрагмент XML:

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

Значение узла содержимого может иметь строку, содержащую аббревиатуру, которую я хочу заменить полным значением.

Спасибо, Пол.


person Paul Blackburn    schedule 09.05.2012    source источник
comment
Мне нужно найти все ключи и выяснить, содержится ли ключ в этом значении узлов. Итак, если узел имеет: «Brkt Pivot R», измените его на «Brkt Pivot R».   -  person Paul Blackburn    schedule 09.05.2012
comment
Если вы приведете лучший пример (документ XML и соответствующий желаемый результат), я мог бы помочь.   -  person Dimitre Novatchev    schedule 10.05.2012
comment
@DimitreNovatchev Некоторые аббревиатуры состоят всего из двух букв, например «Br». На самом деле я использую EXSLT, а не Microsoft. Я заметил, что у них есть функция toikenize. Строка PART_DESC_SHORT должна быть размечена пробелом и применена расшифровка аббревиатуры для точного соответствия, а не содержит. Я попробовал оба решения ниже.   -  person Paul Blackburn    schedule 10.05.2012
comment
Пол Блэкберн: Я не вижу никаких сокращений в строковом значении элемента content. Кроме того, он содержит дефис, который будет обозначен как отдельное слово, если разделителем является пробел. Пожалуйста, отредактируйте вопрос и исправьте эти и другие ошибки.   -  person Dimitre Novatchev    schedule 11.05.2012


Ответы (1)


Нет необходимости использовать for-each - это XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">

  <xsl:output indent="yes" method="xml" />

  <xsl:variable name="abbreviations">
    <abbreviation key="Brkt Pivot R">Bracket Pivot R</abbreviation>
    <abbreviation key="Foo">Expanded Foo</abbreviation>
    <abbreviation key="Bar">Expanded Bar</abbreviation>
  </xsl:variable>

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

  <xsl:template match="text()">
    <xsl:variable name="text" select="."/>
    <xsl:variable name="abbreviation" select="msxsl:node-set($abbreviations)/*[@key=$text]"/>
    <xsl:choose>
      <xsl:when test="$abbreviation">
        <xsl:value-of select="$abbreviation"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:copy/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

преобразует любой XML в точную копию, расширяя весь текст, соответствующий аббревиатуре, определенной в переменной abbreviations вверху.

Если вы хотите расширить аббревиатуры только внутри определенных элементов, вы можете изменить второе правило шаблона match="...".

С другой стороны, если вы хотите расширить ЛЮБОЕ появление всех сокращений в тексте, вам нужны циклы - это означает рекурсию в XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">

  <xsl:output indent="yes" method="xml" />

  <xsl:variable name="abbreviations">
    <abbreviation key="Brkt">Bracket</abbreviation>
    <abbreviation key="As">Assembly</abbreviation>
    <abbreviation key="Foo">Expanded Foo</abbreviation>
    <abbreviation key="Bar">Expanded Bar</abbreviation>
  </xsl:variable>

  <!-- Replaces all occurrences of a string with another within a text -->
  <xsl:template name="replace">
    <xsl:param name="text"/>
    <xsl:param name="from"/>
    <xsl:param name="to"/>
    <xsl:choose>
      <xsl:when test="contains($text,$from)">
        <xsl:value-of select="concat(substring-before($text,$from),$to)"/>
        <xsl:call-template name="replace">
          <xsl:with-param name="text" select="substring-after($text,$from)"/>
          <xsl:with-param name="from" select="$from"/>
          <xsl:with-param name="to" select="$to"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$text"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Replace all occurences of a list of abbreviation with their expanded version -->
  <xsl:template name="replaceAbbreviations">
    <xsl:param name="text"/>
    <xsl:param name="abbreviations"/>
    <xsl:choose>
      <xsl:when test="count($abbreviations)>0">
        <xsl:call-template name="replaceAbbreviations">
          <xsl:with-param name="text">
            <xsl:call-template name="replace">
              <xsl:with-param name="text" select="$text"/>
              <xsl:with-param name="from" select="$abbreviations[1]/@key"/>
              <xsl:with-param name="to" select="$abbreviations[1]"/>
            </xsl:call-template>
          </xsl:with-param>
          <xsl:with-param name="abbreviations" select="$abbreviations[position()>1]"/>
        </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="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="text()">
    <xsl:call-template name="replaceAbbreviations">
      <xsl:with-param name="text" select="."/>
      <xsl:with-param name="abbreviations" select="msxsl:node-set($abbreviations)/*"/>
    </xsl:call-template>
  </xsl:template>

</xsl:stylesheet>

Применение этого второго XSLT к

<document>
  <content name="PART_DESC_SHORT" type="text" vse-streams="2" u="22" action="cluster" weight="1">
    Brkt Pivot R
  </content>
</document>

производит

<document>
  <content name="PART_DESC_SHORT" type="text" vse-streams="2" u="22" action="cluster" weight="1">
    Bracket Pivot R
  </content>
</document>

Обратите внимание, что:

  • это решение предполагает, что аббревиатура не перекрывается (например, две отдельные аббревиатуры Brk и Brkt)

  • он использует XSLT 1.0 - лучшее решение, вероятно, возможно с XSLT 2.0

  • такая обработка тяжелых строк, вероятно, довольно неэффективна в XSLT, возможно, лучше написать функцию расширения на каком-то другом языке и вызывать ее из XSLT.

person MiMo    schedule 09.05.2012
comment
Единственное, что PART_DESC_SHORT может иметь текст «Brkt Pivot R» или просто «Brkt» или «Brkt As» и т. д. Фактически последнее значение будет расширено до «Brkt Assembly» по мере расширения 2 терминов. в моем ключе аббревиатуры было бы просто «Brkt» на «Bracket» - person Paul Blackburn; 09.05.2012
comment
Я изменил ваш оператор выбора на: ‹content name=PART_DESC_SHORT type=text› ‹xsl:choose› ‹xsl:when test=$abbreviation› ‹xsl:value-of select=$abbreviation /› ‹/xsl:when› ‹xsl :иначе› ‹xsl:копировать /› ‹/xsl:иначе› ‹/xsl:выбрать› ‹/content› - person Paul Blackburn; 10.05.2012
comment
Эта модификация работает для моего xml, когда значением было «Brkt», но если значение «Brkt Pivot R», это не так. В качестве аббревиатуры я использую только «Brkt», а не «Brkt Pivot R». - person Paul Blackburn; 10.05.2012
comment
Если я обрабатываю XML, который содержит «Brkt Pivot R» в качестве текста любого элемента с помощью моего второго XSLT, я получаю тот же XML с текстом «Bracket Pivot R» — я думаю, это то, что вам нужно. Я не понимаю изменения в операторе choose - XSLT работает так, как в моем ответе. - person MiMo; 10.05.2012
comment
Очень интересно. Хотя у меня, похоже, нет перекрытия аббревиатуры, я заметил, что это не совсем работает, если слово уже расширено, например, «Valve Rocker» расширяется до «Valvee Rocker», где у меня «Valv» расширен до « Клапан'. Кроме того, это должно работать с каждым разделенным словом в строке. Я заметил несколько расширений в слове. Например, у меня есть «BR» на «Подшипник», поэтому «Кронштейн» можно расширить до «Подшипник». - person Paul Blackburn; 10.05.2012
comment
Спасибо за код и пояснения. Я новичок в XSL/XSLT/XPATH. Да, если бы я мог токенизировать строку, как в Java, это сработало бы. - person Paul Blackburn; 10.05.2012
comment
XSLT не разбивает слова — он просто ищет аббревиатуры, используя containing, и таким образом расширяет Valv внутри Valve. Шаблон replace должен быть улучшен для разделения слов (кстати, вам придется определить, что такое слово), но это слишком сложно для XSLT 1.0. - person MiMo; 10.05.2012
comment
... вы могли бы объяснить все это немного лучше в вопросе, я бы сэкономил немного времени - person MiMo; 10.05.2012