0

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...

Thalia
  • 13,637
  • 22
  • 96
  • 190

1 Answers1

1

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"));
Sina Iravanian
  • 16,011
  • 4
  • 34
  • 45
  • Thank you very much... How would I use the second version, to get the attribute value, or to find if it exists ? – Thalia Nov 13 '12 at 15:15
  • 1
    @Mihaela You're welcome. Assuming that you're interested in attributes named `Project` under the `Import` element replace the last line of the second code with: `Select(x => x.Attributes("Project")).Select(x => x.Value).ToArray();` Then you will have an array of attribute values. Please note that the above code still assumes that `ImportGroup`s have a `Label` with the value of `I_NEED_THIS`. If this is not the case you may need to change the second line too. – Sina Iravanian Nov 13 '12 at 22:32