Я должен выбрать только уникальные записи из XML-документа в контексте <xsl:for-each>
цикл. Я ограничен Visual Studio использованием XSL 1.0.
<availList>
<item>
<schDate>2010-06-24</schDate>
<schFrmTime>10:00:00</schFrmTime>
<schToTime>13:00:00</schToTime>
<variousOtherElements></variousOtherElements>
</item>
<item>
<schDate>2010-06-24</schDate>
<schFrmTime>10:00:00</schFrmTime>
<schToTime>13:00:00</schToTime>
<variousOtherElements></variousOtherElements>
</item>
<item>
<schDate>2010-06-25</schDate>
<schFrmTime>10:00:00</schFrmTime>
<schToTime>12:00:00</schToTime>
<variousOtherElements></variousOtherElements>
</item>
<item>
<schDate>2010-06-26</schDate>
<schFrmTime>13:00:00</schFrmTime>
<schToTime>14:00:00</schToTime>
<variousOtherElements></variousOtherElements>
</item>
<item>
<schDate>2010-06-26</schDate>
<schFrmTime>10:00:00</schFrmTime>
<schToTime>12:00:00</schToTime>
<variousOtherElements></variousOtherElements>
</item>
</availList>
Уникальность должна быть основана на значении трех дочерних элементов: schDate
, schFrmTime
и schToTime
. Если два item
элементы имеют те же значения для всех трех дочерних элементов, они - дубликаты. В вышеупомянутом XML объекты один и два являются дубликатами. Остальные уникальны. Как обозначено выше, каждый объект содержит другие элементы, которые мы не хотим включать в сравнение. 'Уникальность' должна быть фактором тех трех элементов и одних.
Я попытался выполнить это через следующее:
availList/item[not(schDate = preceding:: schDate and schFrmTime = preceding:: schFrmTime and schToTime = preceding:: schToTime)]
Идея позади этого состоит в том, чтобы выбрать записи, где нет никакого предыдущего элемента с тем же schDate
, schFrmTime
и schToTime
. Однако его вывод пропускает последний объект. Это вызвано тем, что мой XPath на самом деле исключает объекты, где все дочерние значения элемента подобраны в рамках всего предыдущего документа. Никакой сингл item
исключены соответствия все дочерние элементы последнего объекта - но потому что значение каждого элемента индивидуально присутствует в другом объекте, последний объект.
Я мог получить корректный результат путем сравнения всех дочерних значений как сцепленной строки к тем же связанным значениям для каждого предыдущего объекта. Кто-либо знает о способе, которым я мог сделать это?
I. Как одно выражение XPath:
/*/item[normalize-space() and not(. = preceding-sibling::item)]
II. Более эффективная (XSLT) реализация, с использованием ключей:
<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="kItemByVal" match="item" use="."/>
<xsl:template match="/">
<xsl:copy-of select=
"*/item[generate-id() = generate-id(key('kItemByVal', .))]
"/>
</xsl:template>
</xsl:stylesheet>
И I, и II, при применении к предоставленному XML-документу правильно выбирают/копируют следующие узлы:
<item><schDate>2010-06-24</schDate><schFrmTime>10:00:00</schFrmTime><schToTime>13:00:00</schToTime></item>
<item><schDate>2010-06-25</schDate><schFrmTime>10:00:00</schFrmTime><schToTime>12:00:00</schToTime></item>
<item><schDate>2010-06-26</schDate><schFrmTime>13:00:00</schFrmTime><schToTime>14:00:00</schToTime></item>
<item><schDate>2010-06-26</schDate><schFrmTime>10:00:00</schFrmTime><schToTime>12:00:00</schToTime></item>
Update: В случае если
имеет других детей, то это преобразование:
<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="kItemBy3Children" match="item"
use="concat(schDate, '+', schFrmTime, '+', schToTime)"/>
<xsl:template match="/">
<xsl:copy-of select=
"*/item[generate-id()
= generate-id(key('kItemBy3Children',
concat(schDate,
'+', schFrmTime,
'+', schToTime)
)
)
]
"/>
</xsl:template>
</xsl:stylesheet>
дает желаемый результат.
Техника, которую я видел, заключается в том, чтобы сделать это за два прохода: отсортировать элементы по всем трем ключевым полям, а затем сравнить каждый элемент с предыдущим элементом (вместо всех предыдущих элементов).
Практично ли для вас выполнять два отдельных преобразования? Это значительно упрощает задачу.
Я видел эту технику в старом издании книги Michael Kay's XSLT. Вы можете найти ее в некоторых его примерах кода.