как получить уникальное (отличное) значение элемента на основе другого значения элемента из каждой записи с помощью xslt

Мне нужно получить значение элемента на основе другого значения элемента из каждой записи.

если RECORD_TYPE='ERROR', то я должен распечатать все отдельные (уникальные) значения ERROR_DESC для всех записей в разделе ERRORS:ERROR_DESC.

Каждое описание ошибки должно быть напечатано с новой строки.

<root>
<SellOutRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 1:location id is invalid</ERROR_DESC>
        <RECORD_NO>1</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>336549R-001</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>LA</PRODUCT_LINE>
    </SellOutRecord>
    <SalesInRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 1:location id is invalid</ERROR_DESC>
        <RECORD_NO>1</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>336549R-001</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>LA</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>C</PRODUCT_LINE_TYPE>
    </SalesInRecord>
    <SellOutRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 2:location id is invalid</ERROR_DESC>
        <RECORD_NO>2</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>3X-KN73C-DB</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>HA</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
    </SellOutRecord>
    <SellOutRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 3:SO:transaction currency is invalid</ERROR_DESC>
        <RECORD_NO>3</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>J3</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
    </SellOutRecord>
    <SalesInRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 2:location id is invalid</ERROR_DESC>
        <RECORD_NO>3</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>J3</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
    </SalesInRecord>
    <SalesInRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 3:SI:transaction document id is invalid</ERROR_DESC>
        <RECORD_NO>3</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>J3</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
    </SalesInRecord>
    <SalesInRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 5:SI:transaction currency is null or invalid</ERROR_DESC>
        <RECORD_NO>5</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>J3</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
    </SalesInRecord>
    <InventoryRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 6:product id is invalid</ERROR_DESC>
        <RECORD_NO>6</RECORD_NO>
        <LOCATION_NAME>XYZ XYZ</LOCATION_NAME>
        <PRODUCT_NUMBER>331184-B21</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0S1</PRODUCT_OPTION>
        <PRODUCT_LINE>R8</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
    </InventoryRecord>
    <SellOutRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 6:SO:invoiced net amount is invalid</ERROR_DESC>
        <RECORD_NO>6</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>J3</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
</SellOutRecord>
    <SellOutRecord>
        <RECORD_TYPE>VALID</RECORD_TYPE>
        <RECORD_NO>7</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>J3</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
</SellOutRecord>
    <SellInRecord>
        <RECORD_TYPE>VALID</RECORD_TYPE>
        <RECORD_NO>7</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>J3</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
</SellInRecord>
</root>

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

<root>
<ERROR>record 1:location id is invalid</ERROR>
<ERROR>record 2:location id is invalid</ERROR>
<ERROR>record 3:SO:transaction currency is invalid</ERROR>
<ERROR>record 3:SI:transaction document id is invalid</ERROR>
<ERROR>record 5:SI:transaction currency is null or invalid</ERROR>
<ERROR>record 6:product id is invalid</ERROR>
<ERROR>record 6:SO:invoiced net amount is invalid</ERROR>
</root>

Заранее спасибо.


person user1658369    schedule 23.01.2013    source источник
comment
Это пример проблемы группировки? Вы используете XSLT1.0 или XSLT2.0? Видите ли, в XSLT2.0 группировку можно выполнить по-другому. Спасибо!   -  person Tim C    schedule 23.01.2013


Ответы (2)


И. Решение 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="kErrDescByVal" match="*[RECORD_TYPE='ERROR']/ERROR_DESC"
          use="normalize-space()"/>

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

 <xsl:template match="*/*/*" priority="-1"/>

 <xsl:template match=
 "ERROR_DESC[generate-id() = generate-id(key('kErrDescByVal',normalize-space())[1])]">
  <ERROR><xsl:apply-templates/></ERROR>
 </xsl:template>
</xsl:stylesheet>

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

<root>
    <SellOutRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 1:location id is invalid</ERROR_DESC>
        <RECORD_NO>1</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>336549R-001</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>LA</PRODUCT_LINE>
    </SellOutRecord>
    <SalesInRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 1:location id is invalid</ERROR_DESC>
        <RECORD_NO>1</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>336549R-001</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>LA</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>C</PRODUCT_LINE_TYPE>
    </SalesInRecord>
    <SellOutRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 2:location id is invalid</ERROR_DESC>
        <RECORD_NO>2</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>3X-KN73C-DB</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>HA</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
    </SellOutRecord>
    <SellOutRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 3:SO:transaction currency is invalid</ERROR_DESC>
        <RECORD_NO>3</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>J3</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
    </SellOutRecord>
    <SalesInRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 2:location id is invalid</ERROR_DESC>
        <RECORD_NO>3</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>J3</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
    </SalesInRecord>
    <SalesInRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 3:SI:transaction document id is invalid</ERROR_DESC>
        <RECORD_NO>3</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>J3</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
    </SalesInRecord>
    <SalesInRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 5:SI:transaction currency is null or invalid</ERROR_DESC>
        <RECORD_NO>5</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>J3</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
    </SalesInRecord>
    <InventoryRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 6:product id is invalid</ERROR_DESC>
        <RECORD_NO>6</RECORD_NO>
        <LOCATION_NAME>XYZ XYZ</LOCATION_NAME>
        <PRODUCT_NUMBER>331184-B21</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0S1</PRODUCT_OPTION>
        <PRODUCT_LINE>R8</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
    </InventoryRecord>
    <SellOutRecord>
        <RECORD_TYPE>ERROR</RECORD_TYPE>
        <ERROR_DESC>record 6:SO:invoiced net amount is invalid</ERROR_DESC>
        <RECORD_NO>6</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>J3</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
    </SellOutRecord>
    <SellOutRecord>
        <RECORD_TYPE>VALID</RECORD_TYPE>
        <RECORD_NO>7</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>J3</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
    </SellOutRecord>
    <SellInRecord>
        <RECORD_TYPE>VALID</RECORD_TYPE>
        <RECORD_NO>7</RECORD_NO>
        <LOCATION_NAME>XYZ el</LOCATION_NAME>
        <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
        <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
        <PRODUCT_LINE>J3</PRODUCT_LINE>
        <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
    </SellInRecord>
</root>

получен желаемый правильный результат:

<root>
   <ERROR>record 1:location id is invalid</ERROR>
   <ERROR>record 2:location id is invalid</ERROR>
   <ERROR>record 3:SO:transaction currency is invalid</ERROR>
   <ERROR>record 3:SI:transaction document id is invalid</ERROR>
   <ERROR>record 5:SI:transaction currency is null or invalid</ERROR>
   <ERROR>record 6:product id is invalid</ERROR>
   <ERROR>record 6:SO:invoiced net amount is invalid</ERROR>
</root>

Пояснение:

  1. Использование мюнхийского метода группировки.

  2. Использование normalize-space() для равноправия две строки, которые отличаются только своим пробелом.


II. Решение XSLT 2.0:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:key name="kErrDescByVal" match="*[RECORD_TYPE='ERROR']/ERROR_DESC"
          use="normalize-space()"/>

 <xsl:template match="/*">
     <root>
       <xsl:for-each-group select="*[RECORD_TYPE='ERROR']/ERROR_DESC"
                           group-by="normalize-space()">
       <ERROR><xsl:apply-templates/></ERROR>
     </xsl:for-each-group>
     </root>
 </xsl:template>
</xsl:stylesheet>

Когда это преобразование применяется к тому же XML-документу (выше), получается тот же правильный результат:

<root>
   <ERROR>record 1:location id is invalid</ERROR>
   <ERROR>record 2:location id is invalid</ERROR>
   <ERROR>record 3:SO:transaction currency is invalid</ERROR>
   <ERROR>record 3:SI:transaction document id is invalid</ERROR>
   <ERROR>record 5:SI:transaction currency is null or invalid</ERROR>
   <ERROR>record 6:product id is invalid</ERROR>
   <ERROR>record 6:SO:invoiced net amount is invalid</ERROR>
</root>

Пояснение:

Использование инструкции XSLT 2.0 <xsl:for-each-group> с атрибутом group-by.

person Dimitre Novatchev    schedule 23.01.2013

Я считаю, что это должно сделать это:

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

  <!-- A key for the ERROR_DESC of all items that have an error -->
  <xsl:key name="error" match="root/*[RECORD_TYPE = 'ERROR']/ERROR_DESC" use="."/>

  <xsl:template match="root">
    <root>
      <!-- Use Muenchian grouping to apply templates to distinct ERROR_DESCs -->
      <xsl:apply-templates
        select="*/ERROR_DESC[generate-id(.) = generate-id(key('error', .)[1])]" />
    </root>
  </xsl:template>

  <!-- A template to handle ERROR_DESCs -->
  <xsl:template match="ERROR_DESC">
    <ERROR>
      <xsl:value-of select="."/>
    </ERROR>
  </xsl:template>
</xsl:stylesheet>
person JLRishe    schedule 23.01.2013