XPath найти все совпадения C # XmlDocument - PullRequest
3 голосов
/ 01 февраля 2012

Я пытаюсь выяснить, как найти все совпадения строки в XmlDocument.

XmlNodeList results 
      = document.SelectNodes("Products/Product/fn:matches(.,'" + SearchWord + "')");

Я пытаюсь сравнить innerText продукта.

Приведенный выше пример не работает, но я предполагаю, что мой способ использования функций XPath очень неправильный.

Ответы [ 4 ]

4 голосов
/ 01 февраля 2012

Оцените это выражение XPath 1.0 (знаете ли вы, matches() - это функция XPath 2.0 и не поддерживается в .NET):

Products/Product/descendant::*[contains(text(), 'YourSearchWord')]

Выбирает все элементы, которыеиметь text-node-child, который содержит строку 'YourSearchWord' и является потомком элемента Product, который является дочерним элементом элемента Products, который является дочерним элементом текущего (контекстного) узла.

Вы можете составить выражение XPath с помощью :

string.Format("Products/Product/descendant::*[contains(text(), '{0}')]", 
              SearchWord )

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

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

Подробнее о том, как предотвратить инъекцию XPath, можно узнать в этом ответе :

https://stackoverflow.com/a/6393690/36305

1 голос
/ 01 февраля 2012

Допустим, у вас есть следующий xml

<Names>
    <Name>
        <FirstName>John</FirstName>
        <LastName>Smith</LastName>
    </Name>
    <Name>
        <FirstName>James</FirstName>
        <LastName>White</LastName>
    </Name>
</Names>

Чтобы получить все узлы, используйте выражение XPath / Names / Name.Первая косая черта означает, что узел должен быть корневым узлом.Метод SelectNodes возвращает коллекцию XmlNodeList, которая будет содержать узлы.Чтобы получить значение подузла, вы можете просто проиндексировать XmlNode с именем узла: xmlNode ["FirstName"]. InnerText.

XmlDocument xml = new XmlDocument();
xml.LoadXml(myXmlString); // suppose that myXmlString contains "<Names>...</Names>"

XmlNodeList xnList = xml.SelectNodes("/Names/Name");
foreach (XmlNode xn in xnList)
{
  string firstName = xn["FirstName"].InnerText;
  string lastName = xn["LastName"].InnerText;
  Console.WriteLine("Name: {0} {1}", firstName, lastName);
}

Вывод:

Имя: Джон Смит Имя:Джеймс Уайт

использует это как пример / отправную точку.спасибо

0 голосов
/ 01 февраля 2012

Из ответа на этот дублирующий вопрос :

Данное выражение оценивается как логическое значение, а не как набор узлов.Я предполагаю, что вы хотите проверить, соответствует ли ProjectName параметризованному тексту.В этом случае вам нужно написать

//ErrorTable/ProjectName[text()='{0}']

. Это даст вам список всех узлов (набор узлов), соответствующих данному условию.Этот список может быть пустым, и в этом случае C # -выражение в вашем образце вернет ноль.

В качестве запоздалой мысли: вы можете использовать исходное выражение xpath, но не с SelectSingleNode, нос помощью Evaluate, вот так:

(bool)xmlDocument.CreateNavigator().Evaluate(String.Format("//ErrorTable/ProjectName/text()='{0}'", projectName));
0 голосов
/ 01 февраля 2012

Если я правильно понимаю ваш вопрос, вы можете использовать следующее:

"Products/Product/[.='" + SearchWord + "']"

или использовать такие функции, как contains(), starts-with() или normalize-space() (урезаниеи заменяет последовательный пробел одним пробелом)

"Products/Product/[contains(normalize-space(.), '" + SearchWord + "')]"

...