PDA

Просмотр полной версии : Алгоритм поиска подстроки в XML


marat_sa
07.11.2008, 17:32
Здравствуйте, подскажите пожалуйста, функцию, которая получает некую строку и искала бы совпадения по всем элементам существующего XML, а потом возвращала бы массив путей(массивов) в виде индексов узлов XML дерева до элементов с совпадением %)

public function searchStringInXML(string:String):Array
{
???
}

Например, в такой XML:

var someXML:XML = <xml>
<someNode>
<node1 value1="первый узел" value2="первый подузел"/>
<node2 value1="первый узел" value2="второй подузел"/>
</someNode>

<someNode>
<node1 value1="первый узел" value2="первый подузел"/>
<node2 value1="второй узел" value2="второй подузел"/>
<node3 value1="санузел" value2="второй санузел"/>
</someNode>
</xml>


Делаем
trace(searchStringInXML("второй").toString());
Output: [0, 1], [1, 1], [1, 1], [1, 2]

Получили массив путей до узлов, в аттрибутах которых встречается слово "второй". [0, 1] - первый узел, второй подузел... и т.д.

Пробовал через вложенные 2 цикла for писать с временной xml, потом вконец запутался. Помогите, пожалуйста :rolleyes:

silin
07.11.2008, 19:44
для этого конкретного расклада
public function searchStringInXML(string:String):Array
{
var res:Array = [];
var level0:int = 0;
for each(var node:XML in someXML.*)
{
var level1:int = 0;
for each(var subNode:XML in node.*)
{
for each( var attr:String in subNode.@* ) {
if (attr.indexOf(string) != -1)
{
res.push([level0, level1]);
}
}
level1++;
}
level0++;
}
return res;
}

etc
07.11.2008, 23:33
По-моему, проще оперировать всё-таки с XMLList, предварительно добавив идентификаторы:

var someXML:XML = <xml>
<someNode>
<node1 value1="первый узел" value2="первый подузел"/>
<node2 value1="первый узел" value2="второй подузел"/>
</someNode>

<someNode>
<node1 value1="первый узел" value2="первый подузел"/>
<node2 value1="второй узел" value2="второй подузел"/>
<node3 value1="санузел" value2="второй санузел"/>
</someNode>
</xml>;
someXML..*.(parent().children()[childIndex()].@id = (parent().hasOwnProperty('@id') ? parent().@id.toString()+'_' : '') + childIndex());
var list:XMLList = someXML..*.((attributes().(toString().indexOf('второй') >= 0)).length() > 0);
trace(list.toXMLString());

Но если очень хочется массивы с путями (для редкостных извращенцев), то добавить к вышенаписанному:

var arr:Array = new Array();
var tmp:Array;
list.(hasOwnProperty('@id') && (tmp = @id.toString().split('_')) && (tmp.map(function(item, index, array) { return (parseInt(item)) } )) && arr.push(tmp));
tmp = null;
trace(arr.join('::'));

marat_sa
08.11.2008, 17:56
__etc, код очччччень "читабельный". Но зато кратко и понятно)))
А если, у меня аттрибуты не только id, а разные?

C этим понятно

someXML..*.(parent().children()[childIndex()].@* = ...


А как быть с

(parent().hasOwnProperty('@id')...

etc
08.11.2008, 18:02
Я не понял вопроса. Что значит разные? Это новые дополнительные аттрибуты, с определенным именем.

marat_sa
08.11.2008, 18:13
Че-то да... Это я не понял ответа вашего %)
Все работает прекрасно.
Меня строка смутила:
> По-моему, проще оперировать всё-таки с XMLList, предварительно добавив идентификаторы:
Я думал в исходную someXML добавить имя всех аттрибутов id.
А потом код просмотрел хорошо и разобрался. Спасибо

etc
08.11.2008, 18:15
Но я бы не стал использовать это прям в таком виде, конечно :)

marat_sa
08.11.2008, 18:25
Ну понятно, мне просто принцип был важен. Скелет, так сказать, для опытов и изучения.
Спрошу тогда сразу, чтоб темы не создавать.
Вот делаем мы поиск: indexOf('второй')
Но мы получаем поиск, чувствительный к регистру букв.
Как сделать нечувствительный? Юзать RegExp?
Ну и соответственно wholeWord и прочие стандартные настройки поиска?

etc
08.11.2008, 18:48
Ну сделайте RegExp, как угодно.

BlooDHounD
09.11.2008, 03:30
а может просто сделать toLowerCase? побыстрее будет чем RegExp ...

etc
09.11.2008, 12:57
Ну если только нечувствительный к регистру, то да. А потом можно и регулярки прикрутить :)