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 с более чем одним корневым элементом.