Search code examples
c#xmlxpathdocument

How to read the assembly name from a non SDK style csproj file in C# using XML?


My code is:

var doc = new XPathDocument(projectFilePath);
var nav = doc.CreateNavigator();
var nsmgr = new XmlNamespaceManager(nav.NameTable);
nsmgr.AddNamespace("p", "http://schemas.microsoft.com/developer/msbuild/2003");
var assemblyName = nav.SelectSingleNode("/p:Project/p:PropertyGroup/p:AssemblyName/text()", nsmgr).Value;

However, I find it unreasonable that I must specify the XML namespace when it is an attribute of the root node (<Project>)

So my question is - how can I use the namespace of the root node without replicating it here? Extra bonus points for concise code.

P.S.

I am perfectly aware that I can read the assembly name just be "grepping" the respective line and parsing it. I am specifically interested in XML here.

EDIT 1

The csproj file is:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
  <PropertyGroup>
    <ProjectType>Local</ProjectType>
    <ProductVersion>9.0.30729</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{09082B9A-906C-4A17-A2E5-6C947DAC7C85}</ProjectGuid>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ApplicationIcon>
    </ApplicationIcon>
    <AssemblyKeyContainerName>
    </AssemblyKeyContainerName>
    <AssemblyName>MyApp</AssemblyName>
    <OutputType>Exe</OutputType>
...

Solution

  • After navigating to an element, you can use GetNamespacesInScope() to retrieve the namespace for local scope and use it in your code.

    var doc = new XPathDocument(projectFilePath);
    var nav = doc.CreateNavigator();
    var nsmgr = new XmlNamespaceManager(nav.NameTable);
    nav.MoveToFollowing(XPathNodeType.Element);
    var ns = nav.GetNamespacesInScope(XmlNamespaceScope.Local).FirstOrDefault();
    nsmgr.AddNamespace("p", ns.Value);
    var assemblyName = nav.SelectSingleNode(
        "/p:Project/p:PropertyGroup/p:AssemblyName/text()", nsmgr).Value;