Преобразование последовательности тегов с использованием XSL - PullRequest
2 голосов
/ 20 января 2010

Я новичок в использовании XSL . Я пытаюсь преобразовать файл XML в другой файл XML с другой структурой, используя XSL. Секция input в XML выглядит следующим образом:

<tag>
    <Keyword>Event: Some Text</Keyword>
    <Keyword>Group: Some Text</Keyword>
    <Keyword>Other: Some Text</Keyword>
</tag>

Я бы хотел, чтобы желаемый вывод был:

<tag>
    <event> Some Text </event>
    <group> Some Text </group>
    <other> Some Text </other>
</tag>

Мой текущий XSL файл:

<xsl:for-each select="tag">
    <xsl:if test="starts-with(Keyword, 'Event: ')">
        <event>
          <xsl:value-of select="substring-after(Keyword, 'Event: ')"/>
        </event>
    </xsl:if>
    <xsl:if test="starts-with(Keyword, 'Group: ')">
        <group>
          <xsl:value-of select="substring-after(Keyword, 'Group: ')"/>
        </group>
    </xsl:if>
    <xsl:if test="starts-with(Keyword, 'Other: ')">
        <other>
          <xsl:value-of select="substring-after(Keyword, 'Other: ')"/>
        </other>
    </xsl:if>
</xsl:for-each>

Текущий вывод показывает только узел события и не отображает остальные узлы:

<tag>
    <event> Some Text </event>
</tag>

Я попытался переключить раздел 'group' на раздел 'event' в XSL, однако все дочерние узлы не отображаются, вероятно, из-за упорядочения узлов ключевых слов во входном XML. Так как же я могу прочитать все узлы ключевых слов и преобразовать их в соответствующие новые узлы для отображения?

Ответы [ 3 ]

3 голосов
/ 21 января 2010

@ Пьер: Я правильно понимаю первоначальный вопрос и ваше решение;) Ваш способ построения XML-элементов ИМХО бит hackly . У XSLT есть специальный набор для динамического построения элементов xml. Таким образом, ваш template match = "Keyword" может выглядеть следующим образом

<xsl:template match="Keyword">
  <xsl:variable name="tag" select="normalize-space(substring-before(.,':'))"/>
  <xsl:element name="{$tag}">
    <xsl:value-of select="normalize-space(substring-after(.,':'))"/>
  </xsl:element>
</xsl:template>

Таким образом, у вас есть возможность легко добавлять атрибуты в выходные XML-элементы, если вам это нужно, и не беспокоиться об отключении-выходе-экранировании и т. Д.

2 голосов
/ 20 января 2010

Вот мое решение. Вам не нужно создавать все эти if операторы, используя xsl: element

<xsl:template match="tag">
<xsl:apply-templates select="Keyword"/>
</xsl:template>

<xsl:template match="Keyword">
 <xsl:variable name="tag" select="normalize-space(substring-before(.,':'))"/>
 <xsl:value-of select="concat('&lt;',$tag,'&gt;')" disable-output-escaping="yes"/>
 <xsl:value-of select="normalize-space(substring-after(.,':'))"/>
 <xsl:value-of select="concat('&lt;/',$tag,'&gt;')" disable-output-escaping="yes"/>
</xsl:template>
2 голосов
/ 20 января 2010

У вас есть только один tag элемент. Вы хотите перебрать все его потомков :

<xsl:for-each select="tag/*">

    <xsl:if test="starts-with(., 'Event: ')">
        <event>
          <xsl:value-of select="substring-after(., 'Event: ')"/>
        </event>
    </xsl:if>
    <xsl:if test="starts-with(., 'Group: ')">
        <group>
          <xsl:value-of select="substring-after(., 'Group: ')"/>
        </group>
    </xsl:if>
    <xsl:if test="starts-with(., 'Other: ')">
        <other>
          <xsl:value-of select="substring-after(., 'Other: ')"/>
        </other>
    </xsl:if>
</xsl:for-each>

РЕДАКТИРОВАТЬ : добавлено другое решение (с использованием оригинального решения @ Pierre).
Примечание значение атрибута имени элемента xsl: обернуто в {}, так что оно оценивается как шаблон значения атрибута , а не как буквальная строка :

<xsl:template match="tag">
<xsl:apply-templates select="Keyword"/>
</xsl:template>

<xsl:template match="Keyword">
<xsl:element name="{normalize-space(substring-before(.,':'))}">
 <xsl:value-of select="normalize-space(substring-after(.,':'))"/>
</xsl:element>
</xsl:template>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...