SelectNodes с игнорированием XPath в именах узлов

У меня проблема, похожая на вопрос SelectNodes с игнорированием случаев XPath, но в моем случае проблема с прописными/строчными буквами заключается в узле с именем «приложение» (иногда это «приложение», иногда «приложение»).

Как бы я применил решение другого поста? или другой применяется в этом случае?

XML:

<?xml version="1.0" encoding="utf-16" ?>
<application>
  <forms>
    <action type="update">
      <form uid="" >
      </form>
    </action>
  </forms>
</application>

In C# 3.5:

XmlNode nodex= oXMLDoc1.SelectSingleNode("Application/forms/action/form/@uid")
nodex.Value="UniqueIDx";//nodex is null :S

person VSP    schedule 15.06.2012    source источник
comment
Обязательно ли использовать XPath? Лично я бы использовал LINQ to XML с предложением Where. Всегда ли приложение/приложение является корневым узлом? (Если это так, не можете ли вы просто применить XPath из этого?)   -  person Jon Skeet    schedule 15.06.2012
comment
Интересно... не могли бы вы опубликовать пример для этого случая с LINQ to XML? и один из XPATH с первым узлом в качестве позиции вместо имени? спасибо ^^   -  person VSP    schedule 15.06.2012
comment
@JonSkeet Ups, я забыл ответить вам напрямую, см. верхний пост, пожалуйста   -  person VSP    schedule 15.06.2012


Ответы (4)


Мы можем преобразовать xml и наши переменные в нижний регистр.

string value = "aBc";
XmlNode xmlnode = xmldoc.SelectSingleNode(string.Format("/some/path/add[translate(@key, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = '{0}']", value.ToLower()));
person mykhailovskyi    schedule 18.06.2015
comment
Спасибо за ответ, так как это самый общий ответ, поэтому его можно применять в других ситуациях. - person VSP; 19.06.2015
comment
что означает /some/path/add ?? - person Varadha31590; 31.05.2016

Просто используйте:

*[translate(name(), 'APPLICATION', 'application')='application']
     /forms/action/form/@uid

Это правильно выбирает требуемый атрибут во всех случаях, когда текущий (начальный контекст) узел имеет дочерний элемент с именем, то есть любой заглавной буквой строки "application".

Проверка на основе XSLT:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:template match="/">
     <xsl:value-of select=
      "*[translate(name(), 'APPLICATION', 'application')='application']
          /forms/action/form/@uid"/>
 </xsl:template>
</xsl:stylesheet>

Когда это преобразование применяется к следующему XML-документу:

<aPPliCatioN>
 <forms>
   <action>
    <form uid="xyz"/>
   </action>
 </forms>
</aPPliCatioN>

нужный узел выбирается, и его строковое значение копируется в выходные данные:

xyz

Пояснение:

Надлежащее использование стандартных функций XPath name() и translate() .

person Dimitre Novatchev    schedule 15.06.2012

Прежде всего, я хочу упомянуть, что xml чувствителен к регистру, поэтому приложение означает что-то еще, а не приложение, мне кажется, это должно быть исправлено в коде, который генерирует этот xml, но если у вас нет контроля над этим, возможно, попробуйте что-то вроде этого в качестве вашего xpath:

"Application/forms/action/form/@uid | application/forms/action/form/@uid"

| оператор будет объединять наборы узлов, которые возвращаются из обоих xpath, в этом случае это будет один или другой

person Gertjan Assies    schedule 15.06.2012
comment
Да, я знал, что xml чувствителен к регистру, но фактически сгенерированный xml зависит от третьей стороны, поэтому это было необходимо... Ваш метод работает нормально, но я хотел знать, возможно, с LINQ to XML или получение первого узла по позиции было бы более оптимальным так как в этом решении код пытается получить оба узла... - person VSP; 15.06.2012

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

XmlDocument doc = new XmlDocument();
doc.Load("input.xml");
XmlNode nodex= oXMLDoc1.DocumentElement.SelectSingleNode("forms/action/form/@uid");

как уже было предложено в комментарии.

С XDocument вы бы сделали, например.

XDocument doc = XDocument.Load("input.xml");
doc.Root.Element("forms").Element("action").Element("form").SetAttributeValue("uid", "UniqueIDx");

[править] Комментарий утверждает, что первый пример пути вызывает исключение, вот полный пример, который не создает исключение для меня и использует тот же путь, который был опубликован ранее:

            string xml = @"<application>
  <forms>
    <action type=""update"">
      <form uid="""" >
      </form>
    </action>
  </forms>
</application>";
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);
            XmlNode nodex = doc.DocumentElement.SelectSingleNode("forms/action/form/@uid");
            nodex.Value = "UniqueIDx";

            doc.Save(Console.Out);
person Martin Honnen    schedule 15.06.2012
comment
Попытка вашего первого примера не удалась с исключением nullreferenceException, вместо этого работала с: */forms/action/form/@uid - person VSP; 15.06.2012
comment
С образцом, который вы опубликовали, я думаю, что мое предложение должно сработать, я отредактирую свой пост, чтобы показать полный пример, который не вызывает для меня исключения. - person Martin Honnen; 15.06.2012