2012-01-15 4 views
1

Я хочу выбрать узлы на основе некоторых переменных. код XML:xslt 1.0, выберите группу узлов с ключом

<data> 
    <prot seq="AAA"> 
     <node num="1">1345</node> 
     <node num="1">11245</node> 
     <node num="2">88885</node> 
    </prot> 
    <prot seq="BBB"> 
     <node num="1">678</node> 
     <node num="1">456</node> 
     <node num="2">6666</node> 
    </prot> 
    <prot seq="CCC"> 
     <node num="1">111</node> 
     <node num="1">222</node> 
     <node num="2">333</node> 
    </prot> 
</data> 

XML, что я хочу

<output> 
    <prot seq="AAA"> 
     <node num="1">1345</node> 
     <node num="2">88885</node> 
    </prot> 
    <prot seq="BBB"> 
     <node num="1">678</node> 
     <node num="2">6666</node> 
    </prot> 
    <prot seq="CCC"> 
     <node num="1">111</node> 
     <node num="2">333</node> 
    </prot> 
</data> 

Итак, моя идея была в группе узлов с XSL: ключевой элемент, а затем сделать для-каждого из них , Например:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/> 
    <xsl:key name="by" match="/data/prot" use="concat(@seq,'|',node/@num)"/> 
    <xsl:template match="/"> 
     <root> 
      <xsl:apply-templates select="/data/prot"/> 
     </root> 
    </xsl:template> 
    <xsl:template match="/data/prot"> 
     <xsl:for-each select="./node"> 
      <xsl:for-each select="key('by',concat(current()/../@seq,'|',current()/@num))"> 
       node <xsl:value-of select="./node" /> 
      </xsl:for-each> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

но результат не то, что я ожидал, и я не вижу, что я делаю неправильно. Я бы предпочел сохранить структуру for-each. Это похоже на то, что я неправильно использовал функции группировки xsl: key.

вывод, что я получаю, нежелательная

<root> 
    node 1345 
    node 1345 
    node 678 
    node 678 
    node 111 
node 111</root> 

И код, как он будет протестирован http://www.xsltcake.com/slices/sgWUFu/20

Спасибо!

+0

В качестве побочного примечания - используйте настоящий XSLT-процессор, а не какой-либо «пирог», который может или не может быть доступен, когда вам это нужно, и может быть довольно глючным. Хорошими процессорами XSLT, которые я рекомендую, являются: (XSLT 1.0) MSXML3,4,6, Saxon 6.5.4, .NET XslCompiledTransform, AltovaXML. (XSLT 2.0) Saxon 9.xx, XQSharp, AltovaXML. –

+0

Я просто работаю в этой теме, поэтому я еще не ответил. Однако, если вы ответите, обратитесь ли вы к веб-клиенту xsltcake для проведения тестов? Процессор, который я использую в коде, - firefox, я в основном использую это веб-приложение для упрощения проблемы, и, если я не могу решить, отправьте его здесь. – Gerard

+0

Жерар, я бы не рекомендовал xslcake любому другу - он бета-версия, ненадежная (может быть недоступна в любой момент), и элементарная DOS-атака задержит ее надолго), она использует разные XSLT-процессоры, производящие разные результаты (в зависимости от браузера, который отправляет запрос) и иногда приводят к нелепым результатам. Сами авторы предупреждают своих пользователей о состоянии и полезности этого приложения. Я рекомендую использовать хорошую XSLT IDE, такую ​​как XSelerator или в списке Kernow. –

ответ

2

Основная проблема в вашем коде является то, что ключевые индексы prot элементы, но то, что мы хотим, чтобы де-дублировать (и нужно проиндексировать) является node элементы.

Вот краткое и верное решение:

<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="nodeByParentAndNum" match="node" 
    use="concat(generate-id(..), '+', @num)"/> 

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

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

<xsl:template match= 
"node 
    [not(generate-id() 
     = 
     generate-id(key('nodeByParentAndNum', 
         concat(generate-id(..), '+', @num) 
         ) 
         [1] 
        ) 
     ) 
    ] 
"/> 
</xsl:stylesheet> 

, когда это преобразование применяется на поставленном XML документа:

<data> 
    <prot seq="AAA"> 
     <node num="1">1345</node> 
     <node num="1">11245</node> 
     <node num="2">88885</node> 
    </prot> 
    <prot seq="BBB"> 
     <node num="1">678</node> 
     <node num="1">456</node> 
     <node num="2">6666</node> 
    </prot> 
    <prot seq="CCC"> 
     <node num="1">111</node> 
     <node num="1">222</node> 
     <node num="2">333</node> 
    </prot> 
</data> 

разыскиваемый, правильный результат производства :

<data> 
    <prot seq="AAA"> 
     <node num="1">1345</node> 
     <node num="2">88885</node> 
    </prot> 
    <prot seq="BBB"> 
     <node num="1">678</node> 
     <node num="2">6666</node> 
    </prot> 
    <prot seq="CCC"> 
     <node num="1">111</node> 
     <node num="2">333</node> 
    </prot> 
</data> 
+0

спасибо, ты указал мне на правильное решение :) – Gerard

+0

@Gerard: Добро пожаловать. –

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