Мюнховский метод для вложенных групп

я задал аналогичный вопрос перед мюнхенским методом для вложенных элементов но на этот раз проблема в другом. мой ввод xml -

<?xml version="1.0" encoding="UTF-8"?> 
<foo>  <bar>bar</bar> 
       <bar>bar</bar> 
       <foobar>
               <baz>baz</baz>
               <baz>baz</baz>
      </foobar>
       <foobar>foobar</foobar>
</foo>

Вывод с использованием xslt должен быть

 <?xml version="1.0" encoding="UTF-8"?>

 <foo>  
 <s> 
 <s> 
 <bar>bar</bar>  
 <bar>bar</bar>
 </s>
 <s> 
 <foobar>
 <s>
 <baz>baz</baz>
 <baz>baz</baz>
  </s>
</foobar>
 <foobar>foobar></foobar>
 </s> 
 </s>
</foo>

если какой-либо элемент-потомок находится в последовательности, код также должен поместить их в тег s. файл xslt, который помещает элементы (а не элементы-потомки), -

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

  <xsl:key name="kGroupLeader" match="*" use="generate-id(self::*[name() != name(preceding-sibling::*[1])])
   " />

<xsl:template match="*/">
<xsl:copy>
  <s>
    <xsl:for-each select="*[key('kGroupLeader', generate-id())]">
      <s>
        <xsl:copy-of select=". | following-sibling::*[
          name() = name(current())
          and
          generate-id(current()) = generate-id(
            preceding-sibling::*[key('kGroupLeader', generate-id())][1]
          )
        ]" />
      </s>
    </xsl:for-each>
  </s>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Я использовал потомок или сам :: * вместо *, но не получил правильного вывода. Что может быть решением. Большое спасибо.


person Community    schedule 21.03.2014    source источник


Ответы (1)


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

 <xsl:template match="*[*]">

В этом случае вам не потребуется создавать самый внешний элемент s, но вы все равно будете перебирать «лидеров групп» с помощью xsl:for-each, как и раньше. , но вместо xsl:copy-of следует использовать xsl:apply-templates, чтобы шаблон вызывался рекурсивно, что позволяло использовать его для элементов-потомков.

Попробуйте этот XSLT

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

    <xsl:key name="kGroupLeader" match="*" 
             use="generate-id(self::*[name() != name(preceding-sibling::*[1])])" />

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

    <xsl:template match="*[*]">
        <xsl:copy>
            <xsl:for-each select="*[key('kGroupLeader', generate-id())]">
              <s>
                <xsl:apply-templates select=". | following-sibling::*[
                      name() = name(current())
                      and generate-id(current()) = generate-id(
                        preceding-sibling::*[key('kGroupLeader', generate-id())][1]
                      )
                    ]" />
              </s>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Обратите внимание на то, что здесь используется Identity Template для копирования всех остальных узлов в документе.

РЕДАКТИРОВАТЬ: обратите внимание, я не совсем уверен, что это считается мюнхианской группировкой, поскольку ключ содержит только первый элемент в каждой «группе», а не все элементы, которые должны быть окружены элементом s.

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

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

    <xsl:key name="kGroupLeader" match="*" 
             use="generate-id((self::*|preceding-sibling::*)[name() != name(preceding-sibling::*[1])][last()])" />

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

    <xsl:template match="*[*]">
        <xsl:copy>
            <xsl:for-each select="*[name() != name(preceding-sibling::*[1])]">
              <s>
                <xsl:apply-templates select="key('kGroupLeader', generate-id())" />
              </s>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
person Tim C    schedule 24.03.2014
comment
Вы должны иметь возможность использовать функцию подсчета. Например <xsl:value-of select="count(key('kGroupLeader', generate-id()))" />. Если вы не можете заставить его работать, задайте совершенно новый вопрос здесь, в StackOverflow. Спасибо! - person Tim C; 24.03.2014