Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2011.01.02;
Скачать: [xml.tar.bz2];

Вниз

Работа с XML в пространстве имен   Найти похожие ветки 

 
bss   (2010-09-17 19:33) [0]

Имеем движок MS XML, там есть такой метод у ноды:

function selectNodes(const queryString: WideString): IXMLDOMNodeList;

Рассмотрим следующий XML-документ:

<MainNode>
   <OurNode>
       <ValueNode>номер раз</ValueNode>
   </OurNode>
   <OurNode>
       <ValueNode>номер два</ValueNode>
   </OurNode>
</MainNode>


Как видно, в документе есть две ноды <OurNode>
Допустим, мы имеем ссылку на первую из них в виде:

FirstNode: IXMLDOMNode;

И хотим получить ссылку на ValueNode. Без пространства имен мы делаем так:

FirstNode.selectNodes("OurNode")

И получим нодлист с одной нашей нодой. Но если мы работаем в пространстве имен, то есть начало документа выглядит аля:

<MainNode xmlns="http://наше_пространство_имен">...

Мы работаем в MS XML версии 4 и выше, используем IXMLDomDocument2, сделали:

my_IXMLDomDocument2.setProperty("SelectionNamespaces", "xmlns:tns="http://наше_пространство_имен"")

То selectNodes("OurNode") вообще ничего не выдаст, конечно. Я знаю один способ, сделать:

FirstNode.selectNodes("//tns:OurNode")

Но тогда он найдет не одну ноду, которая лежит внутри конкретной FirstNode, а найдет все <OurNode>, в данном случае в количестве двух штук...

Вопрос в том - как отыскать именно одну ноду, лежащую внутри именно нашей FirstNode, а не вообще все ноды <OurNode> во всем документе?

P.S. Сори, если запутал... Непонятно - задавайте вопросы...


 
xayam ©   (2010-09-17 23:24) [1]


> как отыскать именно одну ноду

первую?
/MainNode/OurNode[position()=1]

> //

рекурсивный спуск может сильно увеличить время обработки


 
bss   (2010-09-18 11:16) [2]

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

То есть, я хочу что-то аля FirstNode.SearchByName("OurNode") чтобы искало внутри ноды FirstNode ноду с именем "OurNode", которая лежит непосредственно внутри FirstNode.

Пока могу придумать только один способ, перебирать по порядку все Child ноды, извлекать их Name и сравнивать с искомым, вручную формируя NodeList... Бред какой-то же... Должна быть возможность делать это автоматически?

Если выразиться по-другому, задача ставится так - есть куча записей вида:

<MyRecord>
   <MyProperty1>...</MyProperty1>
   <MyProperty2>...</MyProperty2>
   <MyProperty3>...</MyProperty3>
</MyRecord>
<MyRecord>
   <MyProperty1>...</MyProperty1>
   <MyProperty2>...</MyProperty2>
   <MyProperty3>...</MyProperty3>
</MyRecord>
<MyRecord>
   <MyProperty1>...</MyProperty1>
   <MyProperty2>...</MyProperty2>
   <MyProperty3>...</MyProperty3>
</MyRecord>


Хочу последовательно бежать по MyRecord"ам и вытаскивать из них свойства, допустим, записывая в свои какие-то переменные...


 
Медвежонок Пятачок ©   (2010-09-18 15:55) [3]

проблема не в самом неймспейсе, а в том что он в документе объявлен без префикса.

при этом если msxml2_tlb.pas был импортирован в D7 то можно выбирать ноды не обращая на неймспейсы.
если же msxml2_tlb.pas из д2010 то он с такими документами не умеет работать
не с документами, у которых есть неймспейс, а с теми, что без префикса.


 
bss   (2010-09-18 21:05) [4]


> если же msxml2_tlb.pas из д2010 то он с такими документами
> не умеет работать

э-э-э-э... А как эти два файла от D7 и от 2010 могут различаться?! Они же описывают COM-объекты, они должны быть одинаковы и собственно реализация поведения то не в msxml2_tlb.pas, а в движке ms xml... Или чего я не понимаю...


 
Inovet ©   (2010-09-18 21:52) [5]

А почему ДМ Клиент в этой ветке сообщает: "Непредвиденная ошибка."?


 
Inovet ©   (2010-09-18 21:53) [6]

> [5] Inovet ©   (18.09.10 21:52)
> Непредвиденная

---------------------------
DMClient
---------------------------
Неопределенная ошибка.
---------------------------
ОК  
---------------------------


 
xayam ©   (2010-09-18 22:36) [7]


> Хочу последовательно бежать по MyRecord"а

первое что приходит в голову, но надо проверить на скорость:

...
ПЕРЕМЕННАЯ:= 1;
while current <> nil do begin
...
current:= ???.selectNodes("/MainNode/MyRecord/MyProperty1[position()=ПЕРЕМЕННАЯ]");
...
ПЕРЕМЕННАЯ++;
...
end;

потому что может быстрее будет сначала отобрать все MyRecord ( /MainNode/MyRecord ) и в цикле пробежавшись отобрать все свойства (child).


 
xayam ©   (2010-09-18 22:41) [8]


> /MainNode/MyRecord/MyProperty1[position()=ПЕРЕМЕННАЯ]

опс, вот так должно быть на память:
/MainNode/MyRecord/child::[position()=ПЕРЕМЕННАЯ]


 
xayam ©   (2010-09-18 22:49) [9]

короче все неправильно, с бодуна я :)


 
bss   (2010-09-19 12:36) [10]


> может быстрее будет сначала отобрать все MyRecord ( /MainNode/MyRecord
> ) и в цикле пробежавшись отобрать все свойства (child).

и какой будет код?!

for i:=0 to <кол-во_эл-ов> - 1 do
begin
   MyArray[i].Property1 := ???.selectNodes("/MainNode/MyRecord/MyProperty1[position()="+IntToStr(i)+"]");
   MyArray[i].Property2 := ???.selectNodes("/MainNode/MyRecord/MyProperty2[position()="+IntToStr(i)+"]");
   MyArray[i].Property3 := ???.selectNodes("/MainNode/MyRecord/MyProperty3[position()="+IntToStr(i)+"]");
...
end;


Так что ли?! И он каждый раз будет формировать список всех свойств по всему документу и отбирать из них i"тый?
Тогда на мой взгляд эффективнее будет так:

AllProperty_1 := ???.selectNodes("/MainNode/MyRecord/MyProperty1");
for i:=0 to AllProperty_1.length - 1 do
begin
   RecordList[i].Property1 := AllProperty_1.item[i].blablabla ;
end;
AllProperty_2 := ???.selectNodes("/MainNode/MyRecord/MyProperty2");
for i:=0 to AllProperty_2.length - 1 do
begin
   RecordList[i].Property2 := AllProperty_2.item[i].blablabla ;
end;
...


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


 
Медвежонок Пятачок ©   (2010-09-19 13:25) [11]

FirstNode.selectNodes("//tns:OurNode")

Но тогда он найдет не одну ноду, которая лежит внутри конкретной FirstNode, а найдет все <OurNode>, в данном случае в количестве двух штук...


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

Вот он все и аурноде и находит.


 
xayam ©   (2010-09-19 13:57) [12]


> он каждый раз будет формировать список

блин ну ты чего, у тебя же selectNodes возвращает IXMLDOMNodeList - список найденных элементов, по нему и надо бегать. Код если дам то "псевдо" ;) ПРИМЕРНО так:

root:= ???.selectNodes("/MainNod/MyRecord");
for i:=0 to root.count - 1 do
begin
 current:= root.item[i];
 properties := current.selectNodes("child::*");
 for j:=0 to properties.count - 1 do
 begin
         .... properties.item[j] ...//конкретное свойство, делай здесь чего хочешь
 end;
end;

извините, если чего неправильно ;)


 
bss   (2010-09-19 14:47) [13]


> Вот он все и аурноде и находит.

ага... То есть, если я сделаю:

>selectNodes("tns:OurNode")

То он найдет все как надо, именно в текущей ноде? Попробую...
Просто selectNodes("OurNode") точно ничего не находит.


> begin
>          .... properties.item[j] ...//конкретное свойство,
>  делай здесь чего хочешь
>  end;

как ты красиво поставил три точки! А откуда я знаю в каким порядке идут эти ноды?! Ведь у меня есть структура:

TMyRecord = record
 MyProperty1: ...
 MyProperty2: ...
...
end;


Продолжим твой код:

root:= ???.selectNodes("/MainNod/MyRecord");
for i:=0 to root.count - 1 do
begin
current:= root.item[i];
properties := current.selectNodes("child::*");
for j:=0 to properties.count - 1 do
begin
        MyRecord1.MyProperty1 := properties.item... КАКОЙ item?!?!
end;
end;


 
xayam ©   (2010-09-19 15:02) [14]


> MyRecord1.MyProperty1 := properties.item... КАКОЙ item?!
> ?!

MyRecord[i].MyProperty[j]:= properties.item[j]  ?


 
xayam ©   (2010-09-19 15:04) [15]


> А откуда я знаю в каким порядке идут эти ноды?!

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


 
xayam ©   (2010-09-19 15:06) [16]


> КАКОЙ item?!?!

ну это я навскидку написал, список обычно так называют, по справке смотри как точно :)


 
xayam ©   (2010-09-19 15:15) [17]


>  КАКОЙ item?!?!

функция должна там быть если точнее - item(i)

> можно по имени текущего элемента определять куда точно записывать

nodeName


 
bss   (2010-09-19 15:34) [18]


> сли не подряд, то можно по имени текущего элемента определять
> куда точно записывать. Не?

и какой мы видим код? Что-то аля:

root:= ???.selectNodes("/MainNod/MyRecord");
for i:=0 to root.count - 1 do
begin
   current:= root.item[i];
   properties := current.selectNodes("child::*");
   for j:=0 to properties.count - 1 do
   begin
       if properties.item[j],nodeName = "my_property1" then MyRecord1.MyProperty1 := properties.item[j].blabla;
       if properties.item[j].nodeName = "my_property2" then MyRecord1.MyProperty2 := properties.item[j].blabla;
 .....
   end;
end;


Так ты себе это представляешь? Ведь некрасиво смотрится. Куда красивше было бы:

root:= ???.selectNodes("/MainNod/MyRecord");
for i:=0 to root.count - 1 do
begin
   current:= root.item[i];
   properties := current.selectNodes("child::*");
   for j:=0 to properties.count - 1 do
   begin
       MyRecord1.MyProperty1 := properties.NodeByName("my_property1").blabla ;
       MyRecord1.MyProperty2 := properties.NodeByName("my_property2").blabla ;
 .....
   end;
end;


Правда ведь? А сделав обертку над "properties.NodeByName" можно было бы добиться проверки обязательности заполнения всех полей, быть уверенным что все Property заполнятся. А в твоем случае как проверять? Как-то отслеживать, а было ли среди всего этого списк пропертей все нужные...


 
xayam ©   (2010-09-19 15:52) [19]


> Ведь некрасиво смотрится

на первую версию сойдет, одна строчка - одно свойство

> А сделав обертку над "properties.NodeByName"

ну как бы никто не мешает ;)

> можно было бы добиться проверки обязательности заполнения
> всех полей, быть уверенным что все Property заполнятся

для этих целей давно есть схемы. Зачем колеса изобретать?


 
xayam ©   (2010-09-19 16:04) [20]


> есть схемы

Про них даже ветка была с тобой

http://www.delphimaster.net/view/15-1271172177

Вопрос скорей только в проверке xml на соответствие xsd с помощью delphi?


 
xayam ©   (2010-09-19 16:10) [21]

кстати в схеме можно и порядок следования жестко задать, насколько я помню, но это наложит ограничение на того кто тебе xml дает. Если что изменишь, он будет менять? Либо если добавлять, то только в конец.


 
bss   (2010-09-20 11:48) [22]


> Ну все правильно, так и должно быть.

спасибо! Все верно, зря я делал "//tns:TagName", он все и искал. Надо было просто "tns:TagName" - ищет именно в конкретной ноде.



Страницы: 1 вся ветка

Форум: "Прочее";
Текущий архив: 2011.01.02;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.51 MB
Время: 0.004 c
2-1281503294
Molnia
2010-08-11 09:08
2011.01.02
Написание службы с циклом


15-1284928164
Юрий
2010-09-20 00:29
2011.01.02
С днем рождения ! 20 сентября 2010 понедельник


15-1285119505
0x00FF00
2010-09-22 05:38
2011.01.02
Очень старая реклама МТС


15-1285062619
nobody
2010-09-21 13:50
2011.01.02
Где и как лучше хранить пароль к БД?


2-1286535934
noob_one
2010-10-08 15:05
2011.01.02
Как из переменной перечисляемого типа получить строку





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский