Цикл через XSLT - PullRequest
       24

Цикл через XSLT

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

У меня есть какой-то XML, который выглядит следующим образом

<Data>

<MainItem>
<ItemGroup>Foo</ItemGroup>
<ItemDetails>Details</ItemDetails>
</MainItem>

<MainItem>
<ItemGroup>Bar</ItemGroup>
<ItemDetails>Details</ItemDetails>
</MainItem>

<MainItem>
<ItemGroup>Baz</ItemGroup>
<ItemDetails>Details</ItemDetails>
</MainItem>

<OtherData>
<ItemGroup>Foo</ItemGroup>
<OtherDataDetails>Blah</OtherDataDetails>
</OtherData>

<OtherData>
<ItemGroup>Bar</ItemGroup>
<OtherDataDetails>BlahBlah</OtherDataDetails>
</OtherData>

<OtherData>
<ItemGroup>Baz</ItemGroup>
<OtherDataDetails>BlahBlahBlahBlahBlah</OtherDataDetails>
</OtherData>

</Data>

То, что я пытаюсь преобразовать, выглядит примерно так:

Foo
- Details
- Blah

Bar
- Details
- BlahBlah

Baz
- Details
- BlahBlahBlahBlahBlah

с использованием XSLT 1.0.

В настоящее время я выполняю группировку, выполняя что-то похожее на мюнхенский метод ;но я не уверен, как ввести данные из тегов в мою группу.Любые советы?

Ответы [ 3 ]

2 голосов
/ 01 июня 2011

Следующее решение для группировки не использует циклы и заботится о любом другом элементе брата после ItemGroup.Кроме того, для идентификации групп используется только маленький ключ на основе MainItem.


XSLT 1.0 в Saxon 6.5.5

Создание текста:

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

    <xsl:key name="main" match="MainItem/ItemGroup" use="text()"/>

    <xsl:template match="/Data">
        <xsl:apply-templates select="MainItem"/>
    </xsl:template>

    <xsl:template match="MainItem">
        <xsl:value-of select="ItemGroup"/><xsl:text>&#xA;</xsl:text>
        <xsl:apply-templates select="ItemGroup[generate-id(.)=generate-id(key('main', current()/ItemGroup)[1])]"/>
    </xsl:template>

    <xsl:template match="ItemGroup">
        <xsl:apply-templates select="/Data/*[ItemGroup = current()]/*/following-sibling::*"/>
        <xsl:text>&#xA;</xsl:text>
    </xsl:template>

    <xsl:template match="*">
        <xsl:text>- </xsl:text><xsl:value-of select="."/><xsl:text>&#xA;</xsl:text>
    </xsl:template>

</xsl:stylesheet>

Применительно к вашему вводу получается:

 Foo
- Details
- Blah

Bar
- Details
- BlahBlah

Baz
- Details
- BlahBlahBlahBlahBlah

Создание вывода XML:

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

    <xsl:key name="main" match="MainItem/ItemGroup" use="text()"/>

    <xsl:template match="/Data">
        <xsl:copy>
            <xsl:apply-templates select="MainItem"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="MainItem">
        <xsl:variable name="id" select="ItemGroup"/>
        <Group id="{$id}">
            <xsl:apply-templates select="ItemGroup[generate-id(.)=generate-id(key('main', current()/ItemGroup)[1])]"/>
        </Group>
    </xsl:template>

    <xsl:template match="ItemGroup">
        <xsl:copy-of select="/Data/*[ItemGroup = current()]/*/following-sibling::*"/>
    </xsl:template>

</xsl:stylesheet>

производит:

<Data>
   <Group id="Foo">
      <ItemDetails>Details</ItemDetails>
      <OtherDataDetails>Blah</OtherDataDetails>
   </Group>
   <Group id="Bar">
      <ItemDetails>Details</ItemDetails>
      <OtherDataDetails>BlahBlah</OtherDataDetails>
   </Group>
   <Group id="Baz">
      <ItemDetails>Details</ItemDetails>
      <OtherDataDetails>BlahBlahBlahBlahBlah</OtherDataDetails>
   </Group>
</Data>
2 голосов
/ 01 июня 2011

Попробуйте что-то вроде этого:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" />

    <xsl:key name="groups" match="//ItemGroup" use="text()" />

    <xsl:template match="/">
        <Data>
            <xsl:apply-templates
                select="//ItemGroup[count( . | key('groups', text())[1]) = 1]" />
        </Data>
    </xsl:template>

    <xsl:template match="ItemGroup">
        <xsl:variable name="text" select="text()" />
        <Group><xsl:value-of select="$text" /></Group>
        <xsl:for-each select="/Data/*[ItemGroup = $text]/*[contains(name(), 'Details')]">
            <Detail>- <xsl:value-of select="." /></Detail>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

Я настроил рабочий пример для вас.

1 голос
/ 01 июня 2011

Вот очень короткое и наиболее эффективное преобразование, использующее только шаблоны и ключи:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:key name="kGroupByVal" match="ItemGroup"
  use="."/>
 <xsl:key name="kNonGroupByGroup"
  match="*[not(self::ItemGroup)]" use="../ItemGroup"/>

 <xsl:template match=
  "ItemGroup[generate-id()
            =
             generate-id(key('kGroupByVal',.)[1])
            ]
  ">
 <xsl:value-of select="concat('&#xA;',.)"/>

 <xsl:apply-templates mode="listGroup"
  select="key('kNonGroupByGroup',.)"/>
 </xsl:template>

 <xsl:template match="*" mode="listGroup">
  <xsl:value-of select="concat('&#xA; - ', .)"/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

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

<Data>
    <MainItem>
        <ItemGroup>Foo</ItemGroup>
        <ItemDetails>Details</ItemDetails>
    </MainItem>
    <MainItem>
        <ItemGroup>Bar</ItemGroup>
        <ItemDetails>Details</ItemDetails>
    </MainItem>
    <MainItem>
        <ItemGroup>Baz</ItemGroup>
        <ItemDetails>Details</ItemDetails>
    </MainItem>
    <OtherData>
        <ItemGroup>Foo</ItemGroup>
        <OtherDataDetails>Blah</OtherDataDetails>
    </OtherData>
    <OtherData>
        <ItemGroup>Bar</ItemGroup>
        <OtherDataDetails>BlahBlah</OtherDataDetails>
    </OtherData>
    <OtherData>
        <ItemGroup>Baz</ItemGroup>
        <OtherDataDetails>BlahBlahBlahBlahBlah</OtherDataDetails>
    </OtherData>
</Data>

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

Foo
 - Details
 - Blah
Bar
 - Details
 - BlahBlah
Baz
 - Details
 - BlahBlahBlahBlahBlah

** Пояснение **:

  1. Мюнхенская группировка для получения различных значений ItemGroup.

  2. Ключ , используемый для индексации всех не-ItemGroup элементов по их ItemGroup родному брату.

  3. Пустой шаблон, соответствующий любому текстовому узлу, чтобы предотвратить встроенный XSLT-шаблон для вывода любого текстового узла.

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