2015-10-16 4 views
1

Заранее благодарим за то, что нашли время, чтобы прочитать это.Ключи XSLT 1.0 сравнивают несколько ключей

У меня есть входная XML, который выглядит как

<data> 
<row> 
    <Field1>ABC</Field1> 
    <Field2>123</Field2> 
    <tag3>BLAH</tag3> 
    <tag4>BLAH1</tag4> 
</row> 
<row> 
    <Field1>ABC</Field1> 
    <Field2>789</Field2> 
    <tag3>BLAH</tag3> 
    <tag4>BLAH1</tag4> 
</row> 
<row> 
    <Field1>DEF</Field1> 
    <Field2>456</Field2> 
    <tag3>BLAH3</tag3> 
    <tag4>BLAH4</tag4> 
</row> 
<row> 
    <Field1>456</Field1> 
    <Field2>XYZ</Field2> 
    <tag3>BLAH5</tag3> 
    <tag4>BLAH6</tag4> 
</row> 

Теперь я два ключа, определенную как так

<xsl:key name="Field1Key" match="data/row/Field1/text()" use="."/> 
<xsl:key name="Field2Key" match="data/row/Field2/text()" use="."/> 

Что я делаю с ключами к перебрать уникальные значения Field1 и Field2 составляют

<xsl:for-each select="data/row/Field1/text()[generate-id() = generate-id(key('Field1Key',.)[1])]"> 
    <test> 
     <xsl:value-of select="."/>  
    </test> 
</xsl:for-each> 

<xsl:for-each select="data/row/Field2/text()[generate-id() = generate-id(key('Field2Key',.)[1])]"> 
    <test> 
     <xsl:value-of select="."/>  
    </test> 
</xsl:for-each> 

Который дает мне выход, который выглядит как

<test>ABC</test> 
<test>DEF</test> 
<test>456</test> 
<test>123</test> 
<test>789</test> 
<test>456</test> 
<test>XYZ</test> 

так что моя проблема в том,

Как избежать значения 456 от появления в два раза? не могли бы вы указать мне наиболее эффективный способ достичь этого, поскольку я имею дело с большим количеством данных во входных данных?

спасибо.

ответ

0

так что моя проблема в том,

Как избежать значения 456 от появления в два раза?

Вот простой способ получения желаемого результата без изменения ожидаемого порядка последовательности результирующих элементов:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:key name="kF1" match="Field1" use="."/> 
<xsl:key name="kF2" match="Field2" use="."/> 

<xsl:template match="/*"> 
    <xsl:apply-templates select="row/Field1[generate-id() = generate-id(key('kF1',.)[1])]"/> 
    <xsl:apply-templates select= 
     "row/Field2[generate-id() = generate-id(key('kF2',.)[1]) 
     and 
     not(key('kF1', .))]"/> 
</xsl:template> 

    <xsl:template match="Field1 | Field2"> 
    <test><xsl:value-of select="."/></test> 
    </xsl:template> 
</xsl:stylesheet> 

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

<data> 
    <row> 
     <Field1>ABC</Field1> 
     <Field2>123</Field2> 
     <tag3>BLAH</tag3> 
     <tag4>BLAH1</tag4> 
    </row> 
    <row> 
     <Field1>ABC</Field1> 
     <Field2>789</Field2> 
     <tag3>BLAH</tag3> 
     <tag4>BLAH1</tag4> 
    </row> 
    <row> 
     <Field1>DEF</Field1> 
     <Field2>456</Field2> 
     <tag3>BLAH3</tag3> 
     <tag4>BLAH4</tag4> 
    </row> 
    <row> 
     <Field1>456</Field1> 
     <Field2>XYZ</Field2> 
     <tag3>BLAH5</tag3> 
     <tag4>BLAH6</tag4> 
    </row> 
</data> 

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

<test>ABC</test> 
<test>DEF</test> 
<test>456</test> 
<test>123</test> 
<test>789</test> 
<test>XYZ</test> 

могли бы вы указать мне наиболее эффективный способ достижения этой цели, как я имею дело с большим количеством данных на входе?

Если выполнить сортировку в соответствии с рекомендациями других, это O(N*Log(N)), где N является количество уникальных строк значений элементов Field1 и Field2 в документе источника XML.

Решение выше не выполняет сортировки, а дополнительный not(key('kF1', .))] - это только O(M), где M - число уникальных строковых значений элементов Field2 исходного XML-документа.

Таким образом, это решение является более эффективным, чем использование сортировки для восстановления первоначального заказа - значительно, поэтому в случае «большого количества данных на входе».

+0

Спасибо Dimitre. Метод отлично работает с тем, что мне нужно достичь. Очень признателен. –

+0

@arjunajjarapu, добро пожаловать. –

0

Попробуй так:

XSLT 1,0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/> 

<xsl:key name="Field1or2Key" match="Field1 | Field2" use="."/> 

<xsl:template match="/data"> 
    <output> 
     <xsl:for-each select="(row/Field1 | row/Field2)[generate-id() = generate-id(key('Field1or2Key', .)[1])]"> 
      <test> 
       <xsl:value-of select="."/>  
      </test> 
     </xsl:for-each> 
    </output> 
</xsl:template> 

</xsl:stylesheet> 

Обратите внимание, что порядок узлов отличается. Если это имеет значение, используйте xsl:sort, чтобы получить требуемый заказ.


Добавлено:

Как Dimitre Novatchev ноты, если у вас есть большой вход, сортировка, вероятно, не является оптимальным решением для вас. Я подозреваю, что в заказе нет. Фактически, я не буду публиковать альтернативное решение (что было бы сложнее).

+0

Спасибо Jon. Очень ценю указатель. –

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