I am trying to parse a vcxproj file, using - any method I can (I have tried XPathDocument, XElement, XDocument... nothing works)
The typical project configuration:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="P"> ... </ItemGroup>
<ItemGroup> <C I="..." /> </ItemGroup>
<ItemGroup> <C I="..." /> </ItemGroup>
<ItemGroup> ... </ItemGroup>
<Import Project="aaaaa" />
<PropertyGroup C="..." Label="..."> ... </PropertyGroup>
<Import Project="ooother" />
<ImportGroup Label="E"> </ImportGroup>
<ImportGroup Label="I_NEED_THIS" C="...">
<Import Project="other" Condition="x" Label="L" />
<Import Project="I_NEED_THIS_VALUE" />
</ImportGroup>
<Import Project="bbbbb" />
<ImportGroup Label="Ex"> </ImportGroup>
</Project>
I am trying to get the item(s) from inside the ImportGroup with the Label I_NEED_THIS, I would like to get all of them and be able to check (if they have) their Label, or Condition...
I suspected that the problem may be that there are multiple elements with similar names, so I tried to just get one level at a time,
XElement xmlTree = XElement.Load(projectPath);
XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003";
List<XElement> projectElements = (
from mainElement in xmlTree.Descendants(ns + "Project")
from subElement in mainElement.Elements()
select subElement
).ToList();
if (projectElements.Count == 0)
MessageBox.Show("Nothing is working today");
The above, to be followed with a few foreach loops...
foreach (XElement projectElement in projectElements)
{
List<XElement> importElements = (
from mainElement in projectElement.Descendants(ns + "ImportGroup")
from subElement in mainElement.Elements()
select subElement
).ToList();
...
}
And so on, but when testing even the first loop, the Count of the projectElements was 0...
I have tried it without the namespace as well...
What am I missing ? Thank you...
You can get rid of those calls to Descendants
. Calling Elements
directly should be fine. This is how to achieve this using simple loops:
// we can directly grab the namespace, it's better than hard-coding it
XNamespace ns = xmlTree.Name.Namespace;
// xmlTree itself is the Project element, just to make sure:
Debug.Assert(xmlTree.Name.LocalName == "Project");
// the following is all elements named "ImportGroup" under "Project"
var importGroups = xmlTree.Elements(ns + "ImportGroup");
foreach(XElement child in importGroups)
{
// the following are all "Import" elements under "ImportGroup" elements
var imports = child.Elements(ns + "Import");
foreach (var importElem in imports)
{
Console.WriteLine(importElem.Attribute("Project").Value);
}
}
//This is the output:
//other
//I_NEED_THIS_VALUE
Alternatively you can use the following code, which directly goes to the second element that contains the attribute valued "I_NEED_THIS_VALUE"
:
var elems = xmlTree.Elements(ns + "ImportGroup")
.Where(x => x.Attributes("Label").Any(xattr => xattr.Value == "I_NEED_THIS"))
.Elements(ns + "Import")
.Where(x => x.Attributes("Project").Any(xattr => xattr.Value == "I_NEED_THIS_VALUE"));