昨天需要操作用代码操作csproj文件,实现不同vs版本的切换。
在用XElement读取了csproj文件以后怎么也获取不到想要的对象。
反反复复试验了好多次都不得要领:先看下csproj文件的内容:
<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProjectGuid>{EC9D3364-405E-4931-8148-779183C72A40}</ProjectGuid> <OutputType>Exe</OutputType> <AppDesignerFolder>Properties</AppDesignerFolder> <RootNamespace>AsyncDemo</RootNamespace> <AssemblyName>AsyncDemo</AssemblyName> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PlatformTarget>AnyCPU</PlatformTarget> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> <OutputPath>bin\Debug\</OutputPath> <DefineConstants>DEBUG;TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> </Project>
因为只是为了说明问题,我只截取了一部分csproj文件
我最初的代码是:
XDocument doc = XDocument.Load(@"D:\Demo\AsyncDemo\AsyncDemo\AsyncDemo.csproj"); XElement x = doc.Element("Project");
这个x始终为空,最后分析了下doc对象
果然找到了玄机,这个name并不是一个单纯“project”,还带有命名空间。
那么如何获得这个带有Namespace的节点名哪?
好吧,让我们回过头来看看XElement的构造函数:
public XElement(XName name);
注意哦,参数的类型是XName,而不是string,那么平时为什么能用string哪?XName定义了一个隐式的转换,可以把string隐式的转换成XName。
所以,关于Namespace自然也要从XNamespace入手,然后找一个能够变成XName的方法,察看XNamespace的定义,就可以看到:
public static XName operator +(XNamespace ns, string localName);
只要把XNamespace加上本地名称(string),就是一个XName了,非常简单。
再看看如何创建一个XNamespace:
public static implicit operator XNamespace(string namespaceName);
又是隐式转换。。。来看看具体如何创建一个带namespace的project吧:
static void TestXml() { XDocument doc = XDocument.Load(@"D:\Demo\AsyncDemo\AsyncDemo\AsyncDemo.csproj"); XNamespace v = "http://schemas.microsoft.com/developer/msbuild/2003"; XElement x = doc.Element(v + "Project"); }
定义一个namespace,在使用时直接+string即可。这样就可以得到我们想要的对象了,具体操作代码如下:
static void TestXml() { string path = @"D:\Demo\AsyncDemo\AsyncDemo\AsyncDemo.csproj"; XDocument doc = XDocument.Load(path); XNamespace v = "http://schemas.microsoft.com/developer/msbuild/2003"; var x = doc.Element(v + "Project").Elements(v+"PropertyGroup"); foreach (var e in x) { XElement element = e.Element(v + "AssemblyName"); if(element!=null) { element.SetValue("abcd"); } } doc.Save(path); }
这里面所有需要操作的节点都要采用命名空间加节点名的方式。
希望对您有所帮助……