Выберите все узлы с атрибутом, используя xpath

Я пытаюсь выбрать все узлы, используя root.SelectNodes() с XPath. Для справки см. документацию msdn.

В документе следующем пояснении вы можете также ищите узлы, содержащие атрибуты (поправьте меня, если это действительно неправильное понимание).

Поэтому я использовал следующую строку кода:

XmlNodeList nodes = projectDoc.DocumentElement.SelectNodes("descendant::Compile[attribute::Include]");

И я пытаюсь прочитать следующие данные:

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
    <ItemGroup>
        <Compile Include="ArrayExtensions.cs" />
        <Compile Include="ArrayIterator.cs" />
        <Compile Include="AutoInitializeAttribute.cs" />
        <Compile Include="AutoInitializePriority.cs" />
        <Compile Include="AutoRegisterAttribute.cs" />
        <Compile Include="FormattableExtensions.cs" />
        <Compile Include="Mathematics\PrimeNumbers.cs" />
    </ItemGroup>
</Project>

Как показано в приведенном выше примере кода, я хочу получить все узлы XmlNodes, содержащие атрибут Include. Однако, когда я выполняю свой код, nodes содержит 0 элементов.

Что я здесь делаю неправильно?


person Matthijs    schedule 11.06.2014    source источник
comment
Я сильно подозреваю, что проблема заключается в пространстве имен — на самом деле вам следует искать элементы Compile в пространстве имен http://schemas.microsoft.com/developer/msbuild/2003. Есть ли причина, по которой вам нужно сделать это в XPath? С LINQ to XML это было бы тривиально.   -  person Jon Skeet    schedule 11.06.2014
comment
Нет особой причины, нет, если у вас есть лучшее решение, которое будет очень признательно! Также решение вопроса, который я предоставил, тоже было бы потрясающим, просто для учебных целей.   -  person Matthijs    schedule 11.06.2014


Ответы (1)


Я подозреваю, что причина, по которой он не работает, не имеет ничего общего с частью атрибута - он вообще не может найти элементы, поскольку вы запросили только Compile элементов, тогда как на самом деле в пространстве имен есть только Compile элементов с URI http://schemas.microsoft.com/developer/msbuild/2003.

Для этого с помощью XPath, вероятно, потребуется использовать XmlNamespaceManager. который вы затем передадите в другую перегрузку SelectNodes . Лично я бы вместо этого использовал LINQ to XML:

XDocument doc = XDocument.Load("myfile.xml");
XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003";
var elements = doc.Descendants(ns + "Compile")
                  .Where(x => x.Attribute("Include") != null);

В целом, я считаю, что LINQ to XML намного более чистый API, чем "старый" API на основе XmlDocument.

person Jon Skeet    schedule 11.06.2014
comment
Как я могу использовать Count для этого? Я не вижу XNodeList (или подобного) в XDocument-API. Я пытаюсь сказать, что это возвращает? Список элементов или? - person Matthijs; 11.06.2014
comment
@Matthijs: возвращает IEnumerable<XElement>. Вы можете использовать метод расширения Count() так же, как и с любой другой последовательностью. Если вы хотите List<XElement>, просто добавьте вызов .ToList(). - person Jon Skeet; 11.06.2014