Анализ XML, получение глубоких элементов с определенным именем. (c#)

#c# #xml-parsing

#c# #xml-синтаксический анализ

Вопрос:

Я хотел бы спросить вас о синтаксическом анализе XML, я пробую это многими способами, но никогда не получаю результат, который я «хочу/ожидаю». Я хотел бы получить ВСЕ элементы с определенным именем («PackageReference») и его атрибуты/дочерние элементы(элементы). После этого я сделаю сбор и проанализирую результат, чтобы получить значение атрибута «включить» и значение элемента/атрибута с именем «версия».

пример xml (мои элементы, которые меня интересуют, находятся внизу):

 lt;?xml version="1.0" encoding="utf-8"?gt; lt;Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"gt;  lt;PropertyGroupgt;  lt;AutoGenerateBindingRedirectsgt;truelt;/AutoGenerateBindingRedirectsgt;  lt;IsWebBootstrappergt;falselt;/IsWebBootstrappergt;  lt;PublishUrlgt;publishlt;/PublishUrlgt;  lt;Installgt;truelt;/Installgt;  lt;UpdateIntervalUnitsgt;Dayslt;/UpdateIntervalUnitsgt;  lt;/PropertyGroupgt;  lt;PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' "gt;  lt;DebugSymbolsgt;truelt;/DebugSymbolsgt;  lt;DebugTypegt;fulllt;/DebugTypegt;  lt;Optimizegt;falselt;/Optimizegt;  lt;/PropertyGroupgt;  lt;ItemGroupgt;  lt;Compile Include="Launch.cs" /gt;  lt;Compile Include="Launch.designer.cs"gt;  lt;DependentUpongt;Launch.cslt;/DependentUpongt;  lt;/Compilegt;  lt;Compile Include="Main.cs" /gt;  lt;None Include="Info.plist"gt;  lt;SubTypegt;Designerlt;/SubTypegt;  lt;/Nonegt;  lt;/ItemGroupgt;  lt;ItemGroupgt;  lt;Reference Include="System" /gt;  lt;Reference Include="System.Core" /gt;  lt;/ItemGroupgt;  lt;ItemGroupgt;  lt;ProjectReference Include="....ModelProject.Model.csproj"gt;  lt;Projectgt;{0511395F-513C-4F56-BF87-718CA49BB13B}lt;/Projectgt;  lt;Namegt;Project.Modellt;/Namegt;  lt;/ProjectReferencegt;  lt;/ItemGroupgt;  lt;ItemGroupgt;  lt;PackageReference Include="AutoMapper"gt;  lt;Versiongt;7.0.1lt;/Versiongt;  lt;/PackageReferencegt;  lt;PackageReference Include="GMImagePicker.Xamarin"gt;  lt;Versiongt;2.5.0lt;/Versiongt;  lt;/PackageReferencegt;  lt;PackageReference Include="IdentityModel"gt;  lt;Versiongt;4.1.0lt;/Versiongt;  lt;/PackageReferencegt;  lt;PackageReference Include="Microsoft.AppCenter"gt;  lt;Versiongt;4.3.0lt;/Versiongt;  lt;/PackageReferencegt;  lt;PackageReference Include="Microsoft.AppCenter.Analytics"gt;  lt;Versiongt;4.3.0lt;/Versiongt;  lt;/PackageReferencegt;  lt;PackageReference Include="Microsoft.AppCenter.Crashes"gt;  lt;Versiongt;4.3.0lt;/Versiongt;  lt;/PackageReferencegt;  lt;PackageReference Include="Package.Test" Version="1.1.21" /gt;  lt;/ItemGroupgt;  lt;ItemGroup /gt; lt;/Projectgt;  

Результат должен быть:

 AutoMapper;7.0.1 GMImagePicker.Xamarin;2.5.0 ... ... Package.Test;1.1.21  

Мой код:

 var text = System.IO.File.ReadAllText(@"C:MyGitTestXML3.csproj");   var root = XElement.Parse(text); var packageReferencesElements = root.Descendants("PackageReference"); var packageReferencesElementsAndSelf = root.DescendantsAndSelf("PackageReference"); var packageReferencesElementsOffElement = root.Elements().DescendantsAndSelf("PackageReference");  

Я перепробовал много способов, и лишь немногие из них вы можете увидеть в коде. Я не хочу «заходить» в каждый элемент, у которого есть ребенок, и проверять в цикле, есть ли что-то, что меня может заинтересовать. Должен быть лучший способ. И дело в том, что я не уверен, находятся ли мои элементы, которые я ищу, в 2 слое или даже глубже.

Обновление: этот код работает, чтобы получить мою информацию, когда я знаю, насколько они глубоки… Но когда я не знаю, насколько глубоко это должно быть?

 var root = XElement.Parse(fileString); var itemGroupsELements = root.Elements().Where(x =gt; x.Name.LocalName == "ItemGroup");  var packageReferenceElements = itemGroupsELements.Elements().Where(x =gt; x.Name.LocalName == "PackageReference"); foreach (var packageReference in packageReferenceElements) {  string packageName = packageReference.Attribute("Include").Value;  string version = (packageReference.Attribute("Version") != null)  ? packageReference.Attribute("Version").Value  : packageReference.Value;   _packageList.Add(new Package(){App = app, PackageName = packageName, PackageVersion = version, Project = projectName}); }  

Есть идеи, что я делаю не так? Спасибо!

Ответ №1:

PackageReference (как и все остальные элементы в файле) находится в пространстве имен XML «http://schemas.microsoft.com/developer/msbuild/2003». Вы должны указать пространство имен в своем вызове, чтобы Descendants :

 XNamespace build = "http://schemas.microsoft.com/developer/msbuild/2003"; var packageReferencesElements = root.Descendants(build   "PackageReference");