2010-10-20 3 views
1

У меня есть следующая схема:xslt на разных узлах?

<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> 

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

+0

Хороший вопрос, +1. См. Мой ответ для решения группы Muenchian. –

ответ

2

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

<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-sibling s все еще те, в документе.

Для того, чтобы этот код работал, сначала нужно создать совершенно новый документ, в котором узлы отсортированы по желанию, тогда (в 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> 

Обратите внимание: использование Muenchian методы группировки.

+0

Спасибо, thats perfect. Но я все еще не уверен, почему преобразование, которое я предоставил, не сработало. Можете ли вы указать мне какие-либо ресурсы относительно того, где это пошло не так? – Kyle

+0

@ Zenox: Причина, по которой ваша трансформация не работает, как вы ожидаете, в ваших ожиданиях. Когда вы обрабатываете узлы в отсортированном наборе узлов, узлы по-прежнему сохраняют отношения родства (и других осей) для текущего документа. Вам нужно создать совершенно новый документ, в котором отсортированы узлы - тогда их братья и сестры будут такими, какие вы хотите. –

+0

@ Zenox: Я обновил свой ответ, и теперь он начинается с объяснения проблемы в вашем коде. –

1

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

<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 элементы не братьев и сестер.

Смежные вопросы