Ключ группировки XSLT 1.0 для разных узлов и элементов

Я смотрю на мюнхенскую группировку. Я пытался найти примеры, похожие на мой xml, но ничего не нашел. Большинство примеров хорошо структурированы, а мой сбивает с толку.

Вот сокращенная версия моего XML (обратите внимание, что я не могу изменить структуру XML, потому что это стандартная вещь и не в моих руках), и я использую XSLT 1, потому что система поддерживает только эту версию.

<object>
   <creator id="123">
         <name>ABC</name>
         <city>Hamilton</city>
   </creator> 
   <creator><references>456</references></creator>
   <contact><references>123</references></contact>
   <creator id="456">
         <name>XYZ</name>
         <city>New York</city>
   </creator>
   <associatedParty><references>123</references>
       <role>Sponsor</role>
   </associatedParty>
</object>

Результат, который я хочу:

   <party id="123">
       <name>ABC</name>
       <city>Hamilton</city>
       <role>Creator</role>
       <role>Contact</role>
       <role>Sponsor</role>  
   </party>
   <party id="456">
       <name>XYZ</name>
       <city>New York</city>
       <role>Creator</role>
       <role>Contact</role>
   </party>

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

Я застрял с созданием ключа для их группировки из их атрибута id/references. Насколько я вижу, примеры с использованием xsl:key предназначены только для узлов с одинаковым именем, а опубликованный мной пример имеет разные имена узлов. Любая помощь будет оценена!!!!


person Yun    schedule 15.08.2011    source источник
comment
Хороший вопрос, +1. Смотрите мой ответ для полного решения.   -  person Dimitre Novatchev    schedule 15.08.2011


Ответы (2)


Это преобразование:

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

 <xsl:key name="kRefByVal" match="references"
  use="."/>

 <xsl:key name="kCreatorById" match="creator"
  use="@id"/>

 <xsl:key name="kRoleNameByRef"
      match="*[not(self::associatedParty
                  or
                   self::creator
                   )
              ]"
      use="references"/>

 <xsl:key name="kAssocByRef"
      match="associatedParty"
      use="references"/>

 <xsl:template match="/">
  <xsl:variable name="vReferences" select=
   "*/*/references
         [generate-id()
         =
          generate-id(key('kRefByVal',.)[1])
         ]
   "/>

  <xsl:apply-templates select="$vReferences">
   <xsl:sort select="." data-type="number"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="references" priority="3">
  <party id="{.}">
    <xsl:copy-of select="key('kCreatorById',.)/*"/>
    <xsl:apply-templates select=
     "key('kCreatorById',.)"/>

    <xsl:apply-templates select=
     "key('kRoleNameByRef',.)"/>

    <xsl:copy-of select="key('kAssocByRef',.)/role"/>
  </party>
 </xsl:template>

 <xsl:template match="*[not(self::associatedParty)]">
  <role>
   <xsl:value-of select="name()"/>
  </role>
 </xsl:template>
</xsl:stylesheet>

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

<object>
    <creator id="123">
        <name>ABC</name>
        <city>Hamilton</city>
    </creator>
    <creator>
        <references>456</references>
    </creator>
    <contact>
        <references>123</references>
    </contact>
    <creator id="456">
        <name>XYZ</name>
        <city>New York</city>
    </creator>
    <associatedParty>
        <references>123</references>
        <role>Sponsor</role>
    </associatedParty>
</object>

выдает желаемый правильный результат:

<party id="123">
   <name>ABC</name>
   <city>Hamilton</city>
   <role>creator</role>
   <role>contact</role>
   <role>Sponsor</role>
</party>
<party id="456">
   <name>XYZ</name>
   <city>New York</city>
   <role>creator</role>
</party>
person Dimitre Novatchev    schedule 15.08.2011
comment
Спасибо за ответ :)!!!! хотя я еще не до конца понял, что они все на самом деле означают - person Yun; 18.08.2011

Вы можете использовать этот шаблон:

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

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

  <xsl:template match="/">
    <xsl:apply-templates select="//creator[not(references)]"/>
  </xsl:template>

  <xsl:template match="creator">
    <party id="{@id}">
      <xsl:copy-of select="name"/>
      <xsl:copy-of select="city"/>
      <role>Creator</role>
      <xsl:apply-templates select="../*[not(self::creator) and references = current()/@id]"/>
    </party>

  </xsl:template>

  <xsl:template match="associatedParty" priority="1">
    <xsl:copy-of select="role"/>
  </xsl:template>

  <xsl:template match="*[references]">
    <role>
      <xsl:value-of select="name()"/>
    </role>
  </xsl:template>

</xsl:stylesheet>

Вывод:

<party id="123">
  <name>ABC</name>
  <city>Hamilton</city>
  <role>Creator</role>
  <role>contact</role>
  <role>Sponsor</role>
</party>
<party id="456">
  <name>XYZ</name>
  <city>New York</city>
  <role>Creator</role>
</party>
person Kirill Polishchuk    schedule 15.08.2011
comment
Спасибо за ответ! Это тоже сработало! Мне интересно, может ли кто-нибудь дать обзор этих двух методов. Если какой-либо имеет лучшую производительность, чем другой. - person Yun; 18.08.2011