Возможен ли запрос типа JOIN-а в XPath?

qu-qu
Дата: 15.12.2002 11:30:59
Может и офф-топик, но простите уж - все равно, согласно "генеральной линии партии и правительства", SQL и XML - "близнецы-братья"... :-))

Есть XML-документ, примерно вот такой структуры:
<root>

<SomeTag>
<FullInfoList>
<Info ID="1" Attr1="a11" Attr2="a12" Attr3="a13"/>
<Info ID="2" Attr1="a21" Attr2="a22" Attr3="a23"/>
<Info ID="3" Attr1="a31" Attr2="a32" Attr3="a33"/>
<Info ID="4" Attr1="a41" Attr2="a42" Attr3="a43"/>
....
<Info ID="n" Attr1="an1" Attr2="an2" Attr3="an3"/>
</FullInfoList>
<BriefInfoList>
<Item ID="2"/>
<Item ID="4"/>
</BriefInfoList>
</SomeTag>
<SomeTag>
...
</SomeTag>
...
</root>


Для каждого элемента SomeTag мне необходимо выбрать такие элементы FullInfoList/Info, у которых атрибут ID совпадает с таким же атрибутом ID элементов BriefInfoList/Item.
Т.е. из описанного выше примера - это элементы:

<Info ID="2" Attr1="a21" Attr2="a22" Attr3="a23"/>
<Info ID="4" Attr1="a41" Attr2="a42" Attr3="a43"/>


Можно переформулировать задачу и по-другому: для каждого из элементов BriefInfoList/Item - найди недостающие атрибуты из соответствующих им по ID элементов FullInfoList/Info.

С точки зрения SQL - классический JOIN на двух наборах данных, пересекающихся по полю ID, а вот для XPath - никак не могу найти решения... :-((

Помогите, если можете, или дайте убедительное доказательство того, что такое - невозможно, а то я уже всю голову себе сломал... :-))
izvra
Дата: 15.12.2002 14:55:26
/root/SomeTag/FullInfoList/Info[@ID = ancestor::SomeTag/BriefInfoList/Item/@ID]

удачи
qu-qu
Дата: 15.12.2002 15:35:54
Ага, "квак"-бы не так... :-))

Про ось ancestor я слава БГ еще не забыл и что - через нее можно ссылаться на значения тегов общего предка... (эту замечательную формУлу, которую Вы тут мне привели, я попробовал написать сразу же).
Но в том-то вся и беда (или - чрезмерная "хитрость" XPath), что сравнивает он в "тестах узлов" только скалярные значения, а не наборы данных. Т.е. то, что вы написали - означает: "найди узлы Info, у которых значение атрибута ID совпадает с атрибутом ID первого(!!) элемента BriefInfoList/Item вашего общего предка".

Сделайте 2 файлика в одном каталоге, test.xml и test.xsl, откройте test.xml в IE и убедитесь сами:

<?xml version="1.0"?>
<!-- test.xml -->

<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<root>
<SomeTag>
<FullInfoList>
<Info ID="1" Attr1="a11" Attr2="a12" Attr3="a13"/>
<Info ID="2" Attr1="a21" Attr2="a22" Attr3="a23"/>
<Info ID="3" Attr1="a31" Attr2="a32" Attr3="a33"/>
<Info ID="4" Attr1="a41" Attr2="a42" Attr3="a43"/>
<Info ID="n" Attr1="an1" Attr2="an2" Attr3="an3"/>
</FullInfoList>
<BriefInfoList>
<Item ID="2"/>
<Item ID="4"/>
</BriefInfoList>
</SomeTag>
<SomeTag>
</SomeTag>
</root>


<?xml version='1.0'?>
<!-- test.xsl -->

<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
<xsl:template match="/">
<xsl:for-each
select="/root/SomeTag/FullInfoList/Info[@ID = ancestor(SomeTag)/BriefInfoList/Item/@ID]">
qu-qu <xsl:value-of select="@ID"/>
<xsl:value-of select="@Attr1"/>
<xsl:value-of select="@Attr2"/>
<xsl:value-of select="@Attr3"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>


Возвращается только одна строчка:

qu-qu 2 a21 a22 a23
qu-qu
Дата: 15.12.2002 16:05:24
Вот же ж, блин горелый... :-((

Стоило только изменить версию обработчика, как все заработало:

<?xml version='1.0'?>
<!-- test.xsl

<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
-->

<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<pre>
<xsl:for-each xml:space="preserve"
select="/root/SomeTag/FullInfoList/Info[@ID = ancestor::SomeTag/BriefInfoList/Item/@ID]">
ID <xsl:value-of select="@ID"/> Attr1 = <xsl:value-of select="@Attr1"/>
</xsl:for-each>
</pre>
</xsl:template>
</xsl:stylesheet>



ID 2 Attr1 = a21
ID 4 Attr1 = a41


Спасибо большое за "наводку"!
Но все-таки - что же такое творится в спецификации xmlns:xsl="http://www.w3.org/TR/WD-xsl", что она работает - совсем по-другому?

(только мозги засирает, ей-БГ)
izvra
Дата: 15.12.2002 16:09:09
Вообщето у меня вернулось два результата

Проверте сами:

a.xml

<root>

<SomeTag>
<FullInfoList>
<Info ID="1" Attr1="a11" Attr2="a12" Attr3="a13"/>
<Info ID="2" Attr1="a21" Attr2="a22" Attr3="a23"/>
<Info ID="3" Attr1="a31" Attr2="a32" Attr3="a33"/>
<Info ID="4" Attr1="a41" Attr2="a42" Attr3="a43"/>
<Info ID="n" Attr1="an1" Attr2="an2" Attr3="an3"/>
</FullInfoList>
<BriefInfoList>
<Item ID="2"/>
<Item ID="4"/>
</BriefInfoList>
</SomeTag>
</root>


a.vbs
Dim xml ,node,nodes

set xml = CreateObject("MSXML2.DomDocument")
xml.async = false
xml.load("a.xml")
'msgbox xml.parseError.reason
'
msgbox xml.xml
xml.setProperty "SelectionLanguage", "XPath"
set nodes = xml.selectNodes("/root/SomeTag/FullInfoList/Info[@ID = ancestor::SomeTag/BriefInfoList/Item/@ID]")
for each node in nodes
msgbox node.xml
next
msgbox "ok"
qu-qu
Дата: 15.12.2002 17:48:36
Вот так, блин... (век живи - век учись, а дураком помирать - совсем не хочется).

Оказывается и спецификацию xmlns:xsl="http://www.w3.org/TR/WD-xsl" можно заставить работать "по-честному", голову все-таки ломать не надо... :-))

<?xml version='1.0'?>
<!-- test.xsl -->

<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
<xsl:template match="/">
<pre>
Not In List
<xsl:for-each xml:space="preserve"
select="root/SomeTag/FullInfoList/Info[$all$ ancestor(SomeTag)/BriefInfoList/Item/@ID != @ID]">
ID <xsl:value-of select="@ID"/> Attr1 = <xsl:value-of select="@Attr1"/>
</xsl:for-each>
=================
In List
<xsl:for-each xml:space="preserve"
select="root/SomeTag/FullInfoList/Info[$any$ ancestor(SomeTag)/BriefInfoList/Item/@ID = @ID]">
ID <xsl:value-of select="@ID"/> Attr1 = <xsl:value-of select="@Attr1"/>
</xsl:for-each>
</pre>
</xsl:template>
</xsl:stylesheet>


Замечательный результат:

Not In List
ID 1 Attr1 = a11
ID 3 Attr1 = a31
ID n Attr1 = an1
=================
In List
ID 2 Attr1 = a21
ID 4 Attr1 = a41


Остается только, чтобы какой-нить гуру все-таки ответил: какая из спецификаций W3C для XSL-преобразований является "более правильной"?
<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
или
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

З.Ы. кстати, тот же результат получается если из второго шаблона убрать ключевое слово $any$, выходит, что просто поменяв местами пути к шаблонам сравнения - можно узнать много интересного и нового... :-))
jimmers
Дата: 15.12.2002 18:05:50
"Спецификация" http://www.w3.org/TR/WD-xsl устарела, необходимо использовать http://www.w3.org/1999/XSL/Transform.
Кстати, MS XML Parser 4 об этом предупреждает, если встречает документ со ссылкой на http://www.w3.org/TR/WD-xsl.

Удачи