2015-07-08 2 views
0

У меня есть XML-файл, как что:XML слияния узлов с помощью XSLT

<root> 
<scenario name="film1"> 
    <case name="aaa"> 
    <test name="test1">ok</test> 
    </case> 
    <case name="bbb"> 
    <test name="test2">not ok</test> 
    </case> 
    <case name="aaa"> 
    <test name="test3">not ok</test> 
    </case> 
    <case name="bbb"> 
    <test name="test66">ok</test> 
    </case> 
</scenario> 
</root> 

Конечно есть больше узлов, как сценарий, но я хочу, группа case для каждого сценария. Я ожидаю, что-то вроде этого:

<root> 
<scenario name="fil1"> 
    <case name="aaa"> 
    <test name="test1">ok</test> 
    <test name="test3">not ok</test> 
    </case> 
    <case name="bbb"> 
    <test name="test2">not ok</test> 
    <test name="test66">ok</test> 
    </case> 
</scenario> 
</root> 

Я сделал XSLT-файл:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:template match="root"> 
     <xsl:copy> 
      <xsl:apply-templates/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="scenario"> 
    <scenario> 
     <xsl:attribute name="name"> 
     <xsl:value-of select="@name"/> 
     </xsl:attribute> 
     <xsl:apply-templates/> 
    </scenario> 
    </xsl:template> 
    <xsl:template match ="case"> 
    <case> 
     <xsl:attribute name="name"> 
     <xsl:value-of select="@name"/> 
     </xsl:attribute> 
    </case> 
    </xsl:template> 
</xsl:stylesheet> 

вы знаете, что я должен делать?

+0

Что вы ищете, это группировка в XSLT.Взгляните на группировку мурянцев – Saurav

+0

XSLT 2.0 разрешен? –

+0

нет, это не разрешено :(Я не получаю эту муэнчянскую группировку ... –

ответ

0

Вы говорите, что в вашем вопросе вы хотите сгруппировать case для каждого scenario. Если у вас есть несколько scenario элементов, и хотите сгруппировать case элементы внутри каждого такого элемента, вам нужно будет использовать каскадного ключ:

<xsl:key name="case" match="case" use="concat(../@name, '|', @name)" /> 

Это означает, что если у вас есть два case элемента с тем же name , но в разных элементах scenario, они все равно будут сгруппированы отдельно.

Теперь, для группировки, для каждого оператора case в пределах scenario, вам необходимо найти элементы case, которые встречаются сначала в ключе по заданным параметрам. Это может быть сделано следующим образом:

<xsl:apply-templates select="case[generate-id() = generate-id(key('case', concat(../@name, '|', @name))[1])]" /> 

Чтобы разбить его ...

key('case', concat(../@name, '|', @name)) - Возвращает все элементы с теми же атрибутами

key('case', concat(../@name, '|', @name))[1] - Возвращает первый элемент этого списка

generate-id(key('case', concat(../@name, '|', @name))[1]) - Создает уникальный идентификатор для этого первого элемента, поэтому его можно сравнить с текущим элементом.

Таким образом, вы получаете отличные элементы. После этого вы можете получить детали в «группе» с помощью клавиши снова

<xsl:for-each select="key('case', concat(../@name, '|', @name))"> 

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

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:key name="case" match="case" use="concat(../@name, '|', @name)" /> 
    <xsl:output method="xml" indent="yes"/> 

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

    <xsl:template match="scenario"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*" /> 
      <xsl:apply-templates select="case[generate-id() = generate-id(key('case', concat(../@name, '|', @name))[1])]" /> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match ="case"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*" /> 
      <xsl:for-each select="key('case', concat(../@name, '|', @name))"> 
       <xsl:apply-templates /> 
      </xsl:for-each> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

Как уже упоминалось в комментариях, окончательная статья о таком подходе можно найти на http://www.jenitennison.com/xslt/grouping/muenchian.html, так стоит прочитать его и перечитать его, а затем практиковать, пока вы, наконец, не поймете это.

Также обратите внимание на использование Identity Transform, что означает, что вам не нужно писать шаблон для каждого конкретного элемента, если все, что вы делаете, - это скопировать его без изменений.

+0

Я использовал решение, используя Python, но ваш пост делает меня такой счастливой, потому что кто-то объясняет мне немного. –

0

Я хотел бы использовать что-то вроде этого ...

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:template match="root"> 
     <xsl:copy> 
      <xsl:apply-templates/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="scenario"> 
    <xsl:copy> 
      <xsl:apply-templates select="@*" /> 
      <xsl:apply-templates/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match ="case"> 
    <xsl:param name="thisName"> 
     <xsl:value-of select="@name" /> 
    </xsl:param> 
    <xsl:if test=".=/root/scenario/case[@name=$thisName][1]"> 
     <xsl:copy> 
     <xsl:apply-templates select="@*" /> 
     <xsl:apply-templates select="/root/scenario/case[@name=$thisName]/test" /> 
     </xsl:copy> 
    </xsl:if> 
    </xsl:template> 

    <xsl:template match ="test"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*" /> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match ="@*"> 
    <xsl:copy /> 
    </xsl:template> 
</xsl:stylesheet> 
+0

Это нехорошее решение - прочитайте здесь, почему: http: //www.jenitennison. com/xslt/grouping/muenchian.html - Вы также можете перевернуть несколько ваших шаблонов в один - см. https://en.wikipedia.org/wiki/Identity_transform#Using_XSLT_2 –

+0

Бросьте ему фриккинскую кость. его XSLT, который он изучает. – Michael

0

Стандартный подход в XSLT 1.0 - muenchian группировка.

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

    <xsl:key name="case-by-name" match="case" use="@name"/> 
    <xsl:key name="test-by-case" match="test" use="parent::*/@name"/> 

    <xsl:template match="/root"> 
     <xsl:copy> 
      <xsl:apply-templates select="*"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="scenario"> 
     <xsl:copy> 
      <xsl:copy-of select="@*"/> 
      <!-- process only first cases in groups --> 
      <xsl:apply-templates select="case[generate-id() = generate-id(key('case-by-name', @name)[1])]"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="case"> 
     <xsl:copy> 
      <xsl:copy-of select="@*"/> 
      <!-- copy all tests for corresponding case name --> 
      <xsl:copy-of select="key('test-by-case', @name)"/> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 
+0

Второй ключ избыточен: просто используйте клавишу ' –