Конвертировать xml используя xslt - PullRequest
3 голосов
/ 20 мая 2011

У меня есть следующий xml:

<fo:block font-weight="bold" font-style="italic">Some Text Here</fo:block>

Мне нужно преобразовать его в следующее, используя xsl:

{\b\iSome Text Here\i0\b0\par}

Пока мне удалось выбрать элемент блока с помощью:

<xsl:template match="fo:block">
<xsl:text>{</xsl:text>
    <xsl:apply-templates />
<xsl:text>\par}</xsl:text></xsl:template>

и я вывожу: {Some Text Here\par}

Я борюсь с атрибутами и вставляю их с помощью xsl, может кто-нибудь дать мне пример выбора этих атрибутов и получения желаемого результата?

Ответы [ 3 ]

3 голосов
/ 20 мая 2011

Существует довольно простой способ сделать это в общем, используя режимы шаблонов и инструкцию <xsl:sort>.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="fo:block">
  <xsl:text>{</xsl:text>
  <xsl:apply-templates select="@*" mode="prefix" />
  <xsl:apply-templates select="node()" />
  <xsl:apply-templates select="@*" mode="suffix">
    <xsl:sort order="descending"/>
  </xsl:apply-templates>
  <xsl:text>\par}</xsl:text>
</xsl:template>

<xsl:template match="@font-weight['bold']" mode="prefix">\b</xsl:template>
<xsl:template match="@font-style['italic']" mode="prefix">\i</xsl:template>

<xsl:template match="@font-weight['bold']" mode="suffix">\b0</xsl:template>
<xsl:template match="@font-style['italic']" mode="suffix">\i0</xsl:template>

</xsl:stylesheet>

<xsl:sort order="descending" /> обрабатывает атрибуты в обратном порядке во второй раз, когда используется режим суффикса.

Строго говоря, select="node()" в середине основного шаблона является излишним, но при чтении становится понятнее, что обрабатываются только узлы, а не атрибуты.

Вы можете немного упростить добавление новых атрибутов, заменив существующие шаблоны режима suffix следующим:

<xsl:template match="@*" mode="suffix">
  <xsl:apply-templates select="." mode="prefix" />
  <xsl:text>0</xsl:text>
</xsl:template>

Это просто использует шаблон префикса и добавляет дополнительный 0 в конце. Вы всегда можете переопределить его, если некоторые атрибуты не могут быть обработаны так же, как это.

1 голос
/ 20 мая 2011

Это преобразование является более общим и расширяемым :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my">
 <xsl:output method="text"/>

 <xsl:template match="/*">
  <xsl:variable name="vAttributesResult">
   <xsl:call-template name="processAttributes"/>
  </xsl:variable>

  <xsl:value-of select=
   "concat(substring-before($vAttributesResult, ' '),
           .,
           substring-after($vAttributesResult, ' ')
           )
   "/>
 </xsl:template>

 <xsl:template name="processAttributes">
  <xsl:param name="pattrList" select="@*"/>
  <xsl:param name="pResult" select="' '"/>

  <xsl:choose>
      <xsl:when test="not($pattrList)">
       <xsl:value-of select="$pResult"/>
      </xsl:when>
      <xsl:otherwise>
       <xsl:variable name="vthisResult">
        <xsl:apply-templates select="$pattrList[1]">
         <xsl:with-param name="pResult" select="$pResult"/>
        </xsl:apply-templates>
       </xsl:variable>

       <xsl:call-template name="processAttributes">
        <xsl:with-param name="pattrList" select="$pattrList[position()>1]"/>
        <xsl:with-param name="pResult" select="$vthisResult"/>
       </xsl:call-template>
      </xsl:otherwise>
  </xsl:choose>
 </xsl:template>

 <xsl:template match="@font-weight[.='bold']">
  <xsl:param name="pResult"/>
  <xsl:value-of select="concat('\b', $pResult, '\b0')"/>
 </xsl:template>

 <xsl:template match="@font-style[.='italic']">
  <xsl:param name="pResult"/>
  <xsl:value-of select="concat('\i', $pResult, '\i0')"/>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному документу XML (исправлено, чтобы быть правильно сформированным):

<fo:block font-weight="bold" font-style="italic"
xmlns:fo="some:fo">Some Text Here</fo:block>

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

\i\bSome Text Here\b0\i0

Примечание :

  1. Выможно легко добавить обработку для стольких новых комбинаций атрибутов / значений, сколько необходимо - просто добавьте новый шаблон для нового атрибута.

  2. Если порядок важен, используйте эти шаблоны для обработки атрибутов:

-

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

    <xsl:template match="/*">
        <xsl:text>{</xsl:text>
        <xsl:apply-templates select="@*">
         <xsl:with-param name="pSuff" select="''"/>
         <xsl:sort select="position()"/>
        </xsl:apply-templates>

        <xsl:apply-templates select="node()" />

        <xsl:apply-templates select="@*">
         <xsl:with-param name="pSuff" select="'0'"/>
         <xsl:sort select="position()" order="descending"/>
        </xsl:apply-templates>

        <xsl:text>\par}</xsl:text>
    </xsl:template>

    <xsl:template match="@font-weight['bold']">
      <xsl:param name="pSuff"/>
      <xsl:value-of select="concat('\b',$pSuff)"/>
    </xsl:template>

    <xsl:template match="@font-style['italic']">
      <xsl:param name="pSuff"/>
      <xsl:value-of select="concat('\i',$pSuff)"/>
    </xsl:template>
</xsl:stylesheet>

Это преобразование заимствует идею ответа от @ Flynn1169 и значительно упрощает ее (только 3 шаблона вместо t и никаких режимов) и, что наиболее важно, представляет результаты в соответствии с лексическим порядком атрибутов.

В этом случае результат соответствует лексическому порядку атрибутов, а не их отсортированных имен !:

Если у нас есть этот XML-документ :

    <fo:block font-style="italic" font-weight="bold" 
xmlns:fo="some:fo">Some Text Here</fo:block>

, результат теперь будет:

{\i\bSome Text Here\b0\i0\par}

Примечание : Хотя в модели данных XPath нет ничего как «порядок атрибутов», все процессоры XSLT, с которыми я работаю (более 9) в режиме push-стиля, выдают результаты обработки атрибутов в соответствии с их лексическойзаказ.

1 голос
/ 20 мая 2011
<xsl:template match="fo:block">
    <xsl:text>{</xsl:text>
        <xsl:if test="@font-weight = 'bold'">\b</xsl:if>
        <xsl:if test="@font-style = 'italic'">\i</xsl:if>

        <xsl:apply-templates />

        <xsl:if test="@font-style = 'italic'">\i0</xsl:if>
        <xsl:if test="@font-weight = 'bold'">\b0</xsl:if>
    <xsl:text>\par}</xsl:text>
</xsl:template/>

Также проверьте w3schools.com для получения дополнительной информации о XSLT.

...