xslt на разных узлах? - PullRequest
       12

xslt на разных узлах?

1 голос
/ 21 октября 2010

У меня есть следующая схема:

<parent>
  <child id="1" name="Child 1 Version 1" />
</parent>
<parent>
  <child id="2" name="Child 2 Version 1" />
</parent>
<parent>
  <child id="1" name="Child 1 Version 2" />
</parent>

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

  <xsl:for-each select="//parent/child">
    <xsl:sort select="@id"/>
    <xsl:if test="not(@id=following-sibling::*/@id)">
      <xsl:element name="child">
        <xsl:value-of select="@name"/>
      </xsl:element>
    </xsl:if>
  </xsl:for-each>

Но, похоже, это не работает.Мой вывод по-прежнему содержит все три элемента.Любые идеи о том, что я могу сделать, чтобы исправить мою проблему?

Ответы [ 2 ]

2 голосов
/ 21 октября 2010

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

  <xsl:for-each select="//parent/child"> 
    <xsl:sort select="@id"/> 
    <xsl:if test="not(@id=following-sibling::*/@id)"> 
      <xsl:element name="child"> 
        <xsl:value-of select="@name"/> 
      </xsl:element> 
    </xsl:if> 
  </xsl:for-each> 

Но, похоже, это не работает.Мой вывод все еще содержит все три элемента.Любые идеи о том, что я могу сделать, чтобы исправить мою проблему?

Проблема с этим кодом заключается в , что, хотя узлы находятся в отсортированном наборе узлов, их following-siblings по-прежнему те, что в документе.

Чтобы этот код работал, сначала нужно создать совершенно новый документ, в котором узлы отсортированы нужным образом, затем (в XSLT 1.0 это необходимоиспользовать расширение xxx:node-set() в произведенном RTF, чтобы сделать его обычным XML-документом) в этом документе узлы имеют своих родных братьев по желанию.

Решение :

Это преобразование представляет одно возможное решение XSLT 1.0, которое не требует использования функций расширения:

<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="kchildById" match="child" use="@id"/>

 <xsl:template match="/*">
  <t>
    <xsl:apply-templates select=
    "*/child[generate-id()
            =
             generate-id(key('kchildById',
                             @id)[last()]
                         )
            ]
    "/>
  </t>
 </xsl:template>

 <xsl:template match="child">
  <child>
   <xsl:value-of select="@name"/>
  </child>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному фрагменту XML (завернутый в верхний элемент, чтобы стать хорошосформированный XML-документ и добавление второй версии для id="2"):

<t>
    <parent>
        <child id="1" name="Child 1 Version 1" />
    </parent>
    <parent>
        <child id="2" name="Child 2 Version 1" />
    </parent>
    <parent>
        <child id="1" name="Child 1 Version 2" />
    </parent>
    <parent>
        <child id="2" name="Child 2 Version 2" />
    </parent>
</t>

дает желаемый результат :

<t>
   <child>Child 1 Version 2</child>
   <child>Child 2 Version 2</child>
</t>

Do note : использование метода Мюнхена fили группировка.

1 голос
/ 21 октября 2010

Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kParentByChildId" match="parent" use="child/@id"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="parent[count(.|key('kParentByChildId',
                                            child/@id)[last()]) != 1]"/>
</xsl:stylesheet>

Вывод:

<root>
    <parent>
        <child id="2" name="Child 2 Version 1"></child>
    </parent>
    <parent>
        <child id="1" name="Child 1 Version 2"></child>
    </parent>
</root>

Примечание .Группировка по @id, выбор последней из группы.

Редактировать : На всякий случай это сбивает с толку.Приведенная выше таблица стилей означает: скопировать все, кроме тех, которые child не имеют последних @id того же вида .Таким образом, это не выбор последней группы, а обратная логика, чередование не последнее в группе.

Второе.Почему у тебя не работает?Ну, из-за оси following-sibling.Ваш метод поиска первого в своем роде был из давних времен, когда было мало процессорных ключей реализации.Теперь эти дни прошли.

Итак, эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:template match="t">
        <xsl:for-each select="parent/child">
            <xsl:sort select="@id"/>
            <xsl:if test="not(@id=following::child/@id)">
                <xsl:element name="child">
                    <xsl:value-of select="@name"/>
                </xsl:element>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Вывод:

<child>Child 1 Version 2</child>
<child>Child 2 Version 1</child>

Примечание : following ось,потому что child элементы не имеют братьев и сестер.

...