XPath Query: найти элементы, которые имеют тот же список идентификаторов, что и атрибуты

Мне нужно составить запрос, в котором указаны товары тех типов, из которых товары не были проданы. Имеется в виду, что если предмет относится к типу одежды, а предметы одежды не отображаются в списке транзакций, мне нужно отобразить его.

Это мой XML-файл (извинения за супер-канадский):

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE store [

<!ELEMENT store (product*, transaction*)> 
<!ATTLIST store name CDATA #REQUIRED > 

<!ELEMENT product EMPTY> 
    <!ATTLIST product 
        name ID #REQUIRED 
        type CDATA #REQUIRED 
        price CDATA #REQUIRED 
    > 

    <!ELEMENT transaction EMPTY> 
    <!ATTLIST transaction 
products IDREFS #REQUIRED 
sumPrice CDATA #REQUIRED 
    >

]>
<store name="Gordons">
<product name="beaverCoat" type="clothing" price="100"/>
<product name="hockeyStick" type="equipment" price="30"/>
<product name="hockeyPuck" type="equipment" price="5"/>
<product name="icePick" type="equipment" price="40"/>
<product name="mooseMeat" type="food" price="350"/>
<product name="salmon" type="food" price="15"/>
<transaction products="salmon mooseMeat" sumPrice="365"/>    
<transaction products="hockeyPuck hockeyStick" sumPrice="35"/>
<transaction products="hockeyStick mooseMeat" sumPrice="380"/>
<transaction products="salmon mooseMeat" sumPrice="300"/>
<transaction products="hockeyStick hockeyStick hockeyStick" sumPrice="30"/>
</store>

ЖЕЛАЕМЫЙ ВЫХОД

<transaction products="salmon mooseMeat" sumPrice="365"/>
<transaction products="salmon mooseMeat" sumPrice="300"/>

потому что это транзакции, которые имеют те же продукты, что и другая транзакция (eachother)

МОЯ ПОПЫТКА Я поиграл с некоторыми вопросами, но я просто не могу понять это правильно. Это самое близкое, что я получил:

Вот что я попробовал:

//transaction[id(@products)  = //transaction/@products]

Похоже, это должно сработать - найдите все транзакции, все продукты которых соответствуют атрибуту продуктов других транзакций. Однако это не получает хитов.

1 ответ

Решение

РЕДАКТИРОВАТЬ: Почему-то я думал, что это был вопрос XSLT. Вот один способ, которым вы могли бы сделать это только с XPath:

//transaction[(@products = preceding-sibling::transaction/@products or
               @products = following-sibling::transaction/@products)]

Вот как вы можете запросить все такие отдельные элементы (требуется XPath 2.0):

//transaction[(@products = preceding-sibling::transaction/@products or
               @products = following-sibling::transaction/@products) and
               not(concat(@products, '+', @sumPrice) = 
                   preceding-sibling::transaction/concat(@products, '+', @sumPrice))]

Вот один из способов сделать это с помощью XSLT:

<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="kTrans" match="transaction" use="@products" />

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

  <xsl:template match="/*">
    <n>
      <xsl:apply-templates select="transaction[key('kTrans', @products)[2]]" />
    </n>
  </xsl:template>
</xsl:stylesheet>

При запуске на входе образца, результат:

<n>
  <transaction products="salmon mooseMeat" sumPrice="365" />
  <transaction products="salmon mooseMeat" sumPrice="300" />
</n>

Обратите внимание, что я завернул результат в n элемент, потому что недопустимо иметь XML с более чем одним корневым элементом.

Другие вопросы по тегам