Выберите отдельные в XSLT относительно каждого элемента

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

Например, у меня есть следующий XML

<root>
    <sec>
        <nom-title>
            <nom-chapter>
                <nom-article><data att="1.1"/></nom-article>
                <nom-article>
                    <nom-item><data att="1.1"/></nom-item>
                    <nom-item><data att="1.2"/></nom-item>
                </nom-article>
             </nom-chapter>
             <nom-chapter>
                <nom-article><data att="2.1"/></nom-article>
                <nom-article><data att="1.1"/></nom-article>
             </nom-chapter>
         </nom-title>
         <nom-title>
             <nom-chapter>
                 <nom-article><data att="1.1"/></nom-article>
             </nom-chapter>
         </nom-title>
     </sec>
 </root>

И я хочу такой результат:

<root>
    <nom-title>
        <att>1.1</att>
        <att>1.2</att>
        <att>2.1</att>
        <nom-chapter>
            <att>1.1</att>
            <att>1.2</att>
            <nom-article>
                <att>1.1</att>
            </nom-article>
            <nom-article>
                <att>1.1</att>
                <att>1.2</att>
                <nom-item><att>1.1</att></nom-item>
                <nom-item><att>1.2</att></nom-item>
            </nom-article>
         </nom-chapter>
    </nom-title>
    <nom-title>
         <att>1.1</att>
         <nom-chapter>
             <att>1.1</att>
             <nom-article>
                 <att>1.1</att>
             </nom-article>
         </nom-chapter>
     </nom-title>
</root>

Я пытался использовать элемент xsl:key, но он возвращает значение только для одного элемента. В примере он возвращает 1,1 только для первого заголовка, но не для второго. Xsl, который я использовал:

 <xsl:key name="allAtt"
    match="//*[starts-with(name(.),'nom-')]/data"
    use="@att"/>
 <xsl:template match="nom-title|nom-chapter|nom-article|nom-item">
     <xsl:element name="name(.)">
         <xsl:apply-templates select=".//*[starts-with(name(.),'nom-')]/data
     </xsl:element>
 </xsl:template>        
 <xsl:template match="data">
      <xsl:variable name="att" select="@att"/>
      <xsl:if test="generate-id(.)=generate-id(key('allAtt',$att)[1]">
           <xsl:element name="att"><xsl:value-of select="$att"></xsl:element>
      </xsl:if>
 </xsl:template>

person claudex    schedule 04.04.2012    source источник
comment
По моему опыту работы с xslt, для начала нужно иметь действительный xml. Похоже, элемент nom-article не закрыт. Может сначала попробовать исправить.   -  person Justin Nafe    schedule 04.04.2012
comment
Я согласен с Джастином, пожалуйста, сначала покажите нам правильно сформированный образец ввода XML, в настоящее время структура ввода не ясна, некоторые теги не закрыты должным образом (например, <data att="1.1">, <nom-article><data att="2.1"/> ).   -  person Martin Honnen    schedule 04.04.2012
comment
Извините, неправильный копипаст, исправил.   -  person claudex    schedule 04.04.2012


Ответы (1)


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

<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:key name="kData-nom-article" match="data" use=
 "concat(generate-id(ancestor::nom-article[1]),
         '+', @att)"/>
 <xsl:key name="kData-nom-chapter" match="data" use=
 "concat(generate-id(ancestor::nom-chapter[1]),
         '+', @att)"/>
 <xsl:key name="kData-nom-title" match="data" use=
 "concat(generate-id(ancestor::nom-title[1]),
         '+', @att)"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="sec"><xsl:apply-templates/></xsl:template>

 <xsl:template match="nom-title|nom-article|nom-chapter">
  <xsl:copy>
    <xsl:apply-templates mode="list" select=
     ".//data[generate-id()
             =
              generate-id(key(concat('kData-', name(current())),
                              concat(generate-id(current()),
                                     '+', @att
                                    )
                              )
                                [1]
                          )
             ]"/>
    <xsl:apply-templates/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="data" mode="list">
  <att><xsl:value-of select="@att"/></att>
 </xsl:template>

 <xsl:template match="non-item/data">
  <att><xsl:value-of select="@att"/></att>
 </xsl:template>

 <xsl:template match="*[not(self::nom-item)]/data"/>
</xsl:stylesheet>

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

<root>
    <sec>
        <nom-title>
            <nom-chapter>
                <nom-article>
                    <data att="1.1"/>
                </nom-article>
                <nom-article>
                    <nom-item>
                        <data att="1.1"/>
                    </nom-item>
                    <nom-item>
                        <data att="1.2"/>
                    </nom-item>
                </nom-article>
            </nom-chapter>
            <nom-chapter>
                <nom-article>
                    <data att="2.1"/>
                </nom-article>
                <nom-article>
                    <data att="1.1"/>
                </nom-article>
            </nom-chapter>
        </nom-title>
        <nom-title>
            <nom-chapter>
                <nom-article>
                    <data att="1.1"/>
                </nom-article>
            </nom-chapter>
        </nom-title>
    </sec>
</root>

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

<root>
   <nom-title>
      <att>1.1</att>
      <att>1.2</att>
      <att>2.1</att>
      <nom-chapter>
         <att>1.1</att>
         <att>1.2</att>
         <nom-article>
            <att>1.1</att>
         </nom-article>
         <nom-article>
            <att>1.1</att>
            <att>1.2</att>
            <nom-item>
               <data att="1.1"/>
            </nom-item>
            <nom-item>
               <data att="1.2"/>
            </nom-item>
         </nom-article>
      </nom-chapter>
      <nom-chapter>
         <att>2.1</att>
         <att>1.1</att>
         <nom-article>
            <att>2.1</att>
         </nom-article>
         <nom-article>
            <att>1.1</att>
         </nom-article>
      </nom-chapter>
   </nom-title>
   <nom-title>
      <att>1.1</att>
      <nom-chapter>
         <att>1.1</att>
         <nom-article>
            <att>1.1</att>
         </nom-article>
      </nom-chapter>
   </nom-title>
</root>

Объяснение: Выражение трех разных мюнхианских группировок как одной путем динамического построения имени ключа для фактической группировки, которая должна быть выполнена.

Помните: имя ключа представляет собой строку, и при необходимости (как в этом случае) имя может быть создано динамически или передано в качестве параметра.

person Dimitre Novatchev    schedule 04.04.2012