XPath найти все совпадения C# XmlDocument


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

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

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

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

4 3

4 ответа:

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

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

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

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

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

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

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

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

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

Допустим, у вас есть следующий 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"].Внутренний текст.

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);
}

Вывод:

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

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

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

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

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

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

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

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

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

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

Как запоздалая мысль: вы может использовать исходное выражение xpath, но не с SelectSingleNode, а с Evaluate, вот так:

(bool)xmlDocument.CreateNavigator().Evaluate(String.Format("//ErrorTable/ProjectName/text()='{0}'", projectName));