Относительный выбор узла XPath с C # XmlDocument - PullRequest
1 голос
/ 05 июня 2009

Представьте себе следующий XML-документ:

<root>
    <person_data>
        <person>
            <name>John</name>
            <age>35</age>
        </person>
        <person>
            <name>Jim</name>
            <age>50</age>
        </person>
    </person_data>
    <locations>
        <location>
            <name>John</name>
            <country>USA</country>
        </location>
        <location>
            <name>Jim</name>
            <country>Japan</country>
        </location>
    </locations>
</root>

Затем я выбираю личный узел для Джима:

XmlNode personNode = doc.SelectSingleNode("//person[name = 'Jim']");

А теперь из этого узла с одним выбором XPath я хотел бы получить узел местоположения Джима. Что-то вроде:

XmlNode locationNode = personNode.SelectSingleNode("//location[name = {reference to personNode}/name]");

Поскольку я выбираю на основе personNode, было бы удобно, если бы я мог ссылаться на него в списке выбора. Это возможно? .. есть ли связь?

Конечно, я мог бы добавить несколько дополнительных строк кода и поместить имя в переменную и использовать это в строке XPath, но это не то, что я спрашиваю.

Ответы [ 5 ]

3 голосов
/ 05 июня 2009

Это не очень эффективно, но должно работать. Чем больше размер файла, тем медленнее это будет.

string xpath = "//location[name = //person[name='Jim']/name]";
XmlNode locationNode = doc.SelectSingleNode(xpath);

Вот почему это неэффективно:

  • Сокращение "//" вызывает сканирование всех узлов по всему документу.
  • Предикат "[]" выполняется в цикле, один раз для каждого <person>, соответствующего "//person".
  • Второй «//» снова вызывает сканирование всего документа, на этот раз один раз для каждого <person>.

Это означает, что вы получаете квадратичную O (n²) наихудшую производительность, что плохо. Если в вашем документе n <person> s и n <location> s, то выполняется сканирование по всему документу n x n. Все из одного невинно выглядящего выражения XPath.

Я бы рекомендовал против такого подхода. Двухэтапный выбор (сначала найти человека, затем местоположение) будет работать лучше.

1 голос
/ 05 июня 2009

Я не очень уверен, почему вы хотите указать местоположение от personNode. Поскольку имя уже существует в узле location, вы можете использовать его, чтобы получить узел местоположения, соответствующий «Джиму».

XPath would be: //location[name = 'Jim']
1 голос
/ 05 июня 2009

Вы не выбираете узел location на основе узла person, а выбираете его на основе значения узла. Значение - это просто строка, и в этом случае его можно использовать для формулировки условия предиката, которое выбирает узел location на основе значения внутри («Jim»).

0 голосов
/ 23 марта 2010

Я ценю, что ваш настоящий XML-документ более сложен, чем ваш пример, но одна вещь меня поражает. Это напоминает хранилище реляционных данных, содержащее следующее:

  • A person таблица с двумя столбцами - name и age.
  • A location таблица с двумя столбцами - name и country.
  • Отношение 1-1 между двумя таблицами, объединяющими два столбца name.

Имея это в виду, XPath становится очевидным. Вы просто выбираете по первичному ключу значение таблицы, данные которой вы хотите.

//location[name = 'Jim']

Я знаю, что aJ уже предложил это решение, и оно было отклонено, но если вы обобщите идею для реальной XML-схемы, вы получите следующее:

//real_2nd_table_name[real_2nd_pk_column_name_1 = real_1st_pk_column_value_1 and real_2nd_pk_column_name_2 = real_1st_pk_column_value_2 and real_2nd_pk_column_name_3 = real_1st_pk_column_value_3 ...]

Другими словами:

  1. Вы уже знаете значения PK, используемые для поиска строки в первой таблице.
  2. Вы знаете, как связаны две таблицы.
  3. Следовательно, вы должны научиться выражать запрос PK во второй таблице, используя те же значения, которые вы использовали бы для выбора строки в первой таблице.
0 голосов
/ 19 августа 2009
XmlNode locationNode = personNode.SelectSingleNode(".."); 

Должен это сделать.

...