Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > XML, XSL > Выборка из дерева XML


Автор: svch 22.7.2010, 22:03
Добрый день !
Пишу сейчас сайт на обычном ASP. Сайт будет привязан к файлу XML.
Подскажите пож-та, как мне получить следующий результат:
Код

<catalog>
    <Группа Код="111" Наименование="Имя1">
        <Группа Код="222" Наименование="Имя2">
            <Группа Код="333" Наименование="Имя3">
                <Группа Код="444" Наименование="Имя4">
                    <Группа Код="555" Наименование="Имя5">
...


Мне нужно получить список всех родительских групп, т.е. 

если Request("id") = 111, то нужно:
<A HREF='catalog.asp?id=111">Имя1</A>

если Request("id") = 333, то нужно:
<A HREF='catalog.asp?id=111">Имя1</A>
<A HREF='catalog.asp?id=222">Имя2</A>
<A HREF='catalog.asp?id=333">Имя3</A>

и т.д.
Я, признаться, с XML раньше не работал, поэтому и синтаксиса не знаю пока, и все эти шаблоны для меня в диковину. Может подскажет кто ресурс с примерами ? Желательно на русском ?
А вот, что я в файле asp пишу:

Код

Set xmlParser = CreateObject("Msxml2.DOMDocument")
xmlParser.async = False
xmlParser.load "C:\base.xml"
Set colNodes = xmlParser.selectNodes("//catalog/Группа[(@Код=" & Request("id") & "]")
For Each nodeNode In colNodes
    Response.Write "<A HREF='catalog.asp?id=" & nodeNode.attributes.getNamedItem("Код").Text & "'>" & nodeNode.attributes.getNamedItem("Наименование").Text & "</A>"
Next
Set xmlParser = Nothing


Направьте на путь, как говорится.
Большое спасибо.
С уважением, Сергей.

Автор: diadiavova 22.7.2010, 22:09
Справочник здесь
http://msdn.microsoft.com/ru-ru/library/ms256177.aspx
А нужное тебе выражение здесь
Код

ancestor::*

Автор: svch 23.7.2010, 09:31
Спасибо за указанный вектор.
Справочник настолько обширный, но поиск по ancestor уводит меня либо на SQL Server, либо на Visual Studio.
Я вижу - Вы хорошо владеете материалом. Не могли бы помочь конкретным примером ? Как в моем случае надо писать ?

Буду премного благодарен.
С уважением, Сергей.

Автор: Zloxa 23.7.2010, 09:48
Код

//Группа[@Код = 333]/ancestor-or-self::Группа

вместо
Код

//catalog/Группа[(@Код=" & Request("id") & "]"


http://www.mizar.dk/XPath/Default.aspx

Автор: svch 23.7.2010, 11:32
Вот, что получаю:
Expected token 'eof' found ':'. //Группа[@Код=333]/ancestor-or-self-->

Автор: diadiavova 23.7.2010, 11:52
Цитата(svch @  23.7.2010,  10:31 Найти цитируемый пост)
Справочник настолько обширный

В этом справочнике слева есть панель навигации и я дал ссылку на корневой узел справочника. В частности справка по осям здесь
http://msdn.microsoft.com/ru-ru/library/ms256456.aspx
Цитата(svch @  23.7.2010,  10:31 Найти цитируемый пост)
Как в моем случае надо писать ?

В ситуации, когда из хмл-файла надо извлечь данные и построить из них какой-то документ, лучше воспользоваться XSLT. Пример программного преобразования здесь
http://msdn.microsoft.com/en-us/library/ms762796(VS.85).aspx
Чтобы получить ссылку из группы, понадобится такой шаблон
Код

    <xsl:template match="Группа">
        <a href="{concat('catalog.asp?id=', @Код)}">
            <xsl:value-of select="@Наименование"/>
        </a>
    </xsl:template>

А там, где для конкретного узла надо вставить список ссылок, построенный из родительских групп просто написать
Код

<xsl:apply-templates select="ancestor::Группа"/>

Если решишь оставить как есть, то 4-ю строку кода напиши так
Код

Set colNodes = xmlParser.selectNodes("//catalog/Группа[(@Код=" & Request("id") & "]/ancestor::Код")

Если я правильно понял смысл кода ессно

Автор: svch 23.7.2010, 12:06
Нет, та же самая ошибка. Вы там, кстати, скобку забыли.
Код

Expected token 'eof' found ':'. //catalog/


XML у меня вот такой :
Код

<?xml version="1.0" encoding="windows-1251"?>
<catalog>
    <Группа Код="000002" Наименование="Имя1">
        <Группа Код="000180" Наименование="Имя2">
            <Элемент Код="309151">
                <Характеристики Вес="" Высота=""/>
            </Элемент>
            <Элемент Код="309155">
                <Характеристики Вес="" Высота=""/>
            </Элемент>
            <Элемент Код="310021">
                <Характеристики Вес="" Высота=""/>
            </Элемент>
            <Элемент Код="310027">
                <Характеристики Вес="" Высота=""/>
            </Элемент>
        </Группа>
        <Группа Код="000008" Наименование="Имя3">
            <Группа Код="000856" Наименование="Имя4">
                <Элемент Код="52652">
                    <Характеристики Вес="" Высота=""/>
                </Элемент>
            </Группа>
        </Группа>
...

Автор: diadiavova 23.7.2010, 12:15
Цитата(svch @  23.7.2010,  13:06 Найти цитируемый пост)
Нет, та же самая ошибка.

А так?
Код

        Set colNodes = xmlParser.selectNodes("//catalog/Группа[@Код='" & Request("id") & "']/ancestor::Группа")


Автор: svch 23.7.2010, 12:21
То же самое :(

Автор: Zloxa 23.7.2010, 12:23
Цитата(diadiavova @  23.7.2010,  12:15 Найти цитируемый пост)
//catalog/Группа

сматчит только группы первого уровня, нужно "//Группа"
Цитата(diadiavova @  23.7.2010,  12:15 Найти цитируемый пост)
ancestor

не захватит искомый элемент, надо ancestor-or-self

но судя по
Цитата(svch @  23.7.2010,  11:32 Найти цитируемый пост)
Expected token 'eof' found ':'.

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

Автор: Zloxa 23.7.2010, 12:55
Код

Sub xmltest()
  Debug.Print "------------------------- start"
  Set xmlParser = CreateObject("Msxml2.DOMDocument")
  xmlParser.async = False
  xmlParser.LoadXML ("<catalog><Группа Код=""111""><Группа Код=""222""><Группа Код=""333""><Группа Код=""444""></Группа></Группа></Группа></Группа></catalog>")
  Debug.Print "parsed with error:" & xmlParser.parseError.reason
  xmlParser.setProperty "SelectionLanguage", "XPath"
  Set colNodes = xmlParser.SelectNodes("//Группа[@Код = 222]/ancestor-or-self::Группа")
  For Each nodeNode In colNodes
     Debug.Print nodeNode.Attributes.getNamedItem("Код").Text
  Next
  Set xmlParser = Nothing
  Debug.Print "------------------------- finsih"
End Sub

------------------------- start
parsed with error:
111
222
------------------------- finsih


Автор: svch 23.7.2010, 13:13
Спасибо Вам !
Код

xmlParser.setProperty "SelectionLanguage", "XPath"


Без этой строки не работало.
А если необходимо сделать обратный вариант ?
Т.е.
Код

<catalog>
    <Группа Код="111" Наименование="Имя1">
        <Группа Код="222" Наименование="Имя2">
            <Группа Код="333" Наименование="Имя3">
                <Группа Код="444" Наименование="Имя4">
                    <Группа Код="555" Наименование="Имя5">
...

если Request("id") = 111, то нужно получить все вложенные Группы:
<A HREF='catalog.asp?id=111">Имя1</A>
<A HREF='catalog.asp?id=222">Имя2</A>
<A HREF='catalog.asp?id=333">Имя3</A>
<A HREF='catalog.asp?id=444">Имя4</A>
<A HREF='catalog.asp?id=555">Имя5</A>

С уважением, Сергей.


Автор: Zloxa 23.7.2010, 13:29
Цитата(svch @  23.7.2010,  13:13 Найти цитируемый пост)
А если необходимо сделать обратный вариант ?

Код

//Группа[@Код = ???]/descendant-or-self::Группа

Автор: svch 23.7.2010, 15:16
Вот спасибо, добрый человек !
Что почитать мне лучше ? Тут же не справочник нужен, а чтоб разжевали по полочкам.

С уважением, Сергей.

Автор: Zloxa 23.7.2010, 15:32
Цитата(svch @  23.7.2010,  15:16 Найти цитируемый пост)
Что почитать мне лучше ?

Мне, в свое время показался весьма неплохим http://xml.nsu.ru/.
В частнеости там об http://xml.nsu.ru/xpath/xpath_home.xml

Автор: disketa 15.10.2011, 14:22
Подскажите пожалуйста и мне.

Есть файл xml с данными в нём содержаться данные, часть из которых надо выводить при определёном условии, делаю так:

For i = 0 To xml.getElementsByTagName("page").Length-1
if link.item(0).childNodes(i).getAttribute("url")="default.asp" then 
Response.write "Вывод данных..."
end if
next

Можно ли не перебором проверять на соответсвие условия, а сделать выборку xml с нужными условиеми?

Автор: diadiavova 15.10.2011, 16:17
Цитата(disketa @  15.10.2011,  15:22 Найти цитируемый пост)
Можно ли не перебором проверять на соответсвие условия, а сделать выборку xml с нужными условиеми? 

Можно. XPath в твоем случае будет выглядеть примерно так
Код

//page[@url = 'default.asp']
Ну это если надо из всех элементов page в документе выбрать те, у который данный атрибут имеет соответствующее значение(более конкретно ты не написал).

Автор: disketa 15.10.2011, 17:50
Это с эканомит память, ну тоесть при этом будет загружаться не весь XML файл?
И можно этот код привести в рамках моего кода, а то я в XML почти не разбираюсь?

Автор: diadiavova 15.10.2011, 18:09
Цитата(disketa @  15.10.2011,  18:50 Найти цитируемый пост)
Это с эканомит память, ну тоесть при этом будет загружаться не весь XML файл?

Это вряд ли, но поможет все записать одной строкой.
Цитата(disketa @  15.10.2011,  18:50 Найти цитируемый пост)
И можно этот код привести в рамках моего кода, а то я в XML почти не разбираюсь?

В рамках твоего кода не совсем понятно, что такое link.item(0) и что именно ты вибираешь. То есть, если это какой-то элемент документа и тебе надо выбрать его дочерние элементы page, то видим как-то так
Код

Dim pages 
Set pages = link.item(0).selectNodes("page[@url = 'default.asp']")

Если же речь о том, что надо получить все узлы-потомки с таким именем, то выражение приобретет вид
Код

Set pages = link.item(0).selectNodes(".//page[@url = 'default.asp']")

Таким образом ты получишь коллекцию узлов, удовлетворяющий условию. Но для того, чтобы вывести поочередно эту коллекцию в исходящий поток, тебе все равно понадобится цикл, так что в данном простейшем случае ты сэкономишь только на конструкции If.

Автор: disketa 15.10.2011, 18:24
Приведу весь код:

Код

Set xml = Server.CreateObject("Microsoft.XMLDOM")
xml.async = False
xml.setProperty "ServerHTTPRequest", true
xml.Load(server.mappath("list.xml"))
If xml.parseError.errorCode=0 Then
Set link = xml.getElementsByTagName("pages")
For i = 0 To xml.getElementsByTagName("page").Length-1
url=link.item(0).childNodes(i).getAttribute("url")
if url="default.asp" then 
Set ob = link.item(0).childNodes(i)
Set ob1 = ob.getElementsByTagName("link")
For j = 0 To ob1.Length-1 
u=ob1.item(j).childNodes(2).text
t=ob1.item(j).childNodes(1).text
Response.write u & "<br>" & t 
next
end if
next
end if


Данный код не всегда выполняется либо очень долго выполняется, файл xml около 10Мб, или серверу не хватает памяти, или пока он перебирает все значения (примерно 30000 записей), равные "default.asp" проходит времени больше чем разрешенно на хостинге.
Поэтому ищу способ оптимизации, если можно приведённый Вами код, вставьте в мой пожалуйста, всё равно не понял я как это сделать.

Автор: disketa 15.10.2011, 19:21
Если делаю так:

Код

Set xml = Server.CreateObject("Microsoft.XMLDOM")
xml.async = False
xml.setProperty "ServerHTTPRequest", true
xml.Load(server.mappath("list.xml"))
If xml.parseError.errorCode=0 Then
Set link = xml.getElementsByTagName("pages")
Set ob = link.item(0).selectNodes(".//page[@url = 'default.asp']")
Set ob1 = ob.getElementsByTagName("link")
For j = 0 To ob1.Length-1 
u=ob1.item(j).childNodes(2).text
t=ob1.item(j).childNodes(1).text
Response.write u & "<br>" & t 
next
end if


Обрабатывается быстро теперь, но выводит первое значение из списка, причём где url не равно 'default.asp'
 smile 
Направление действий правельное, но условие видимо должно быть иное!
Расшифруйте пожалуйста эту строку: .//page[@url = 'default.asp']
что она обозначает, может она выбирает значение каторое не равно, но часть значения имеет строку 'default.asp' ?

Автор: disketa 15.10.2011, 22:49
Всё проблему, решил (была ошибка в название параметров).
Спасибо большое, без Вас бы не разобрался с этим XML

Автор: diadiavova 15.10.2011, 23:02
Я не уверен, что все правильно понял, да VBscript знаю плохо, но вроде это то, что надо, по крайней мере суть такая, там уж если что сам поправь, гарантировать нормальную работу кода не могу.
Код

Set xml = Server.CreateObject("Microsoft.XMLDOM")
xml.async = False
xml.setProperty "ServerHTTPRequest", true
xml.Load(server.mappath("list.xml"))
If xml.parseError.errorCode=0 Then
    Set links = xml.selectNodes("//pages//page[@url = 'default.asp']//link")
    Dim link
    For i = 0 To links.Length - 1
         Response.write links(i).childNodes(2).text & "<br>" & links(i).childNodes(1).text 
    Next
End If


Автор: disketa 16.10.2011, 11:08
Вот этот код заработал, как надо:

Код

Set xml = Server.CreateObject("Microsoft.XMLDOM")
xml.async = False
xml.setProperty "ServerHTTPRequest", true
xml.Load(server.mappath("list.xml"))
If xml.parseError.errorCode=0 Then
Set link = xml.getElementsByTagName("pages")
Set ob = link.item(0).selectNodes(".//page[@url = 'default.asp']")
if ob.Length>0 then
Set ob1 = ob.item(0).getElementsByTagName("link") 'Вот здесь была ошибка!!!
For j = 0 To ob1.Length-1 
u=ob1.item(j).childNodes(2).text
t=ob1.item(j).childNodes(1).text
Response.write u & "<br>" & t 
next
end if
end if


Большое спасибо за помощь!

Автор: diadiavova 16.10.2011, 11:16
Цитата(disketa @  16.10.2011,  12:08 Найти цитируемый пост)
Вот этот код заработал, как надо:

А почему не выбрать линки сразу, как у меня, ведь короче намного получается и код понятнее?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)