Справка по XSLT - XSL для различных похожих XML, использование шаблонов - PullRequest
3 голосов
/ 11 ноября 2011

Я очень новичок в XSL и XPath.Извиняюсь, если этот вопрос показывает некоторую глупость.

У меня есть XML что-то вроде

<root>
    <widget name="status">
    ...
        <component name="date">
            <component name="day" label="Fri"/>
            <component name="date" label="4"/>
        </component>
        <component name="time" label="11:23 AM"/>
    ....
    </widget>
    <widget name="foo">
    </widget>
</root>

Мне нужно создать тег DateTime, который будет составлять из всех трех значений что-то вроде пт 4 11:23:00

Я пишу XSL для него.

<DateTime>
    <xsl:value-of select="(//widget[@name="status"]/component[@name='date'])[1]/@label"/>
    <xsl:text> </xsl:text>
    <xsl:value-of select="(//widget[@name="status"]/component[@name='date'])[2]/@label"/>
    <xsl:text> </xsl:text>
    <xsl:value-of select="//widget[@name="status"]/component[@name='time']/@label"/>
</DateTime>

Вопрос:

  1. Я передаю "widget [@ name ="дата "]" для каждого оператора выбора.Есть ли лучший способ сократить xpath.

  2. Мне нужно переместить это в шаблон и вызвать шаблон.какой из них мне следует использовать call-template / apply-templates?

  3. У нас есть набор похожих приложений, которые генерируют эти XML.Приведенный выше XML взят из приложения A.ApplicationB может показывать детали немного по-другому, например, <component name="datetime">Fri 4 11:23 AM</component>.У нас есть почти 3-4 таких приложения, где они отображают детали немного по-другому.

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

Я думаю написать один XSL для всех приложений.

Ответы [ 2 ]

1 голос
/ 11 ноября 2011

Один из способов сделать это с вашим XML-кодом был бы следующим:

<xsl:template match="widget">
  <!-- ... -->
  <xsl:apply-templates select="." mode="create-date-time" />
  <!-- ... -->
</xsl:template>

<xsl:template match="widget" mode="create-date-time">
  <xsl:variable name="date" select="component[@name='date']" />
  <xsl:variable name="time" select="component[@name='time']" />

  <DateTime>
    <xsl:value-of select="normalize-space(
      concat(
        $date/component[@name='day']/@label, ' ', 
        $date/component[@name='date']/@label, ' ',
        $time/@label
      )
    )" />
  </DateTime>
</xsl:template>
  • Я передаю widget[@name="date"] каждому оператору выбора.Есть ли лучший способ сократить xpath.

Используйте <xsl:template> / <xsl:apply-templates> и относительные пути.Храните вещи, которые вам нужны более одного раза, в <xsl:variable>.См. Выше.

  • Мне нужно переместить это в шаблон и вызвать шаблон.какой я должен использовать call-template / apply-templates?

Последний.Всегда переходите на <xsl:apply-templates>, если нет веских причин не делать этого.Как правило: если вы не уверены, то для этого нет веской причины.

  • У нас есть набор похожих приложений, которые генерируют эти XML.Приведенный выше XML взят из приложения A.Приложение B может показывать детали немного по-другому, что-то вроде <component name="datetime">Fri 4 11:23 AM</component> У нас есть почти 3-4 таких приложения, где они отображают детали немного по-другому.

Вы можете расширитьшаблон create-date-time для этого:

<xsl:template match="widget" mode="create-date-time">
  <xsl:variable name="date" select="component[@name='date']" />
  <xsl:variable name="time" select="component[@name='time']" />
  <xsl:variable name="dt"   select="component[@name='datetime']" />

  <DateTime>
    <xsl:value-of select="normalize-space(
      concat(
        $dt/label, ' ',
        $date/component[@name='day']/@label, ' ', 
        $date/component[@name='date']/@label, ' ',
        $time/@label
      )
    )" />
  </DateTime>
</xsl:template>

Если некоторые компоненты отсутствуют, ошибок не будет.normalize-space() обеспечивает отсутствие лишних пробелов для любой комбинации компонентов.

Выше может произойти сбой, если компоненты date + time и datetime не являются взаимоисключающими (я предположил,они есть).Если это не так, или если возникают более сложные случаи, создайте дополнительные специальные шаблоны, такие как этот:

<xsl:template match="widget[component[name='datetime']]" mode="create-date-time">
  <xsl:variable name="dt"   select="component[@name='datetime']" />

  <DateTime>
    <xsl:value-of select="component[@name='datetime']/@label" />
  </DateTime>
</xsl:template>

<xsl:apply-templates> убедится, что вызывается правильный.Просто создайте конкретные match= выражения для каждого возможного случая.

0 голосов
/ 11 ноября 2011

Это простое преобразование (16 строк, один шаблон, полностью стиль push, без переменных, без режимов):

<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=
 "component
    [contains('|day|date|time|',
              concat('|', @name, '|'))
    ]
 ">
     <xsl:value-of select="concat(@label, ' ')"/>
     <xsl:apply-templates/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

при применении к предоставленному XMLдокумент :

<root>
    <widget name="status">
    ...
        <component name="date">
            <component name="day" label="Fri"/>
            <component name="date" label="4"/>
        </component>
        <component name="time" label="11:23 AM"/>
    ....
    </widget>
    <widget name="foo">
    </widget>
</root>

дает в точности нужный результат :

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