2013-10-25 29 views
0

我想读取一个XML文件,并根据一个元素的值我想执行一些代码,然后用一个代码生成替换值,然后保存该文件到一个新的位置。读取一个XML文件,然后写入一个复制版本

我现在这样做的方式非常冗长而且不准确,并且变成了一大麻烦。我想要做的是修改“ClInclude”和“ClCompile”元素。当他们被发现时,我想执行一些代码,然后用新的代码替换当前值,而不是保存它们。我宁愿使用linq to xml方法,而不使用我的XML阅读器和Writer方法。这是一个XML示例。

<?xml version="1.0" encoding="utf-8"?> 
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <ItemGroup Label="ProjectConfigurations"> 
    <ProjectConfiguration Include="Debug|Win32"> 
     <Configuration>Debug</Configuration> 
     <Platform>Win32</Platform> 
    </ProjectConfiguration> 
    <ProjectConfiguration Include="Release|Win32"> 
     <Configuration>Release</Configuration> 
     <Platform>Win32</Platform> 
    </ProjectConfiguration> 
    </ItemGroup> 
    <PropertyGroup Label="Globals"> 
    <ProjectGuid>{57900E99-A405-49F4-83B2-0254117D041B}</ProjectGuid> 
    <Keyword>Win32Proj</Keyword> 
    <RootNamespace>libprojx</RootNamespace> 
    </PropertyGroup> 
    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> 
    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> 
    <ConfigurationType>DynamicLibrary</ConfigurationType> 
    <UseDebugLibraries>true</UseDebugLibraries> 
    <CharacterSet>MultiByte</CharacterSet> 
    <PlatformToolset>v110</PlatformToolset> 
    </PropertyGroup> 
    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> 
    <ConfigurationType>DynamicLibrary</ConfigurationType> 
    <UseDebugLibraries>false</UseDebugLibraries> 
    <WholeProgramOptimization>true</WholeProgramOptimization> 
    <CharacterSet>MultiByte</CharacterSet> 
    <PlatformToolset>v110</PlatformToolset> 
    </PropertyGroup> 
    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> 
    <ImportGroup Label="ExtensionSettings"> 
    </ImportGroup> 
    <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> 
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 
    </ImportGroup> 
    <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> 
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 
    </ImportGroup> 
    <PropertyGroup Label="UserMacros" /> 
    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> 
    <LinkIncremental>true</LinkIncremental> 
    </PropertyGroup> 
    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> 
    <LinkIncremental>false</LinkIncremental> 
    </PropertyGroup> 
    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> 
    <ClCompile> 
     <PrecompiledHeader> 
     </PrecompiledHeader> 
     <WarningLevel>Level3</WarningLevel> 
     <Optimization>MaxSpeed</Optimization> 
     <PreprocessorDefinitions>WIN32;projx_EXPORTS;_DEBUG;_WINDOWS;_USRDLL;LIBprojx_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 
     <AdditionalIncludeDirectories>..\..\Win32;..\..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 
     <BasicRuntimeChecks>Default</BasicRuntimeChecks> 
     <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 
    </ClCompile> 
    <Link> 
     <SubSystem>Windows</SubSystem> 
     <GenerateDebugInformation>true</GenerateDebugInformation> 
     <AdditionalLibraryDirectories>..\..\..\..\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> 
     <AdditionalDependencies>libdirect.lib;%(AdditionalDependencies)</AdditionalDependencies> 
    </Link> 
    </ItemDefinitionGroup> 
    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> 
    <ClCompile> 
     <WarningLevel>Level3</WarningLevel> 
     <PrecompiledHeader> 
     </PrecompiledHeader> 
     <Optimization>MaxSpeed</Optimization> 
     <FunctionLevelLinking>true</FunctionLevelLinking> 
     <IntrinsicFunctions>true</IntrinsicFunctions> 
     <PreprocessorDefinitions>WIN32;projx_EXPORTS;NDEBUG;_WINDOWS;_USRDLL;LIBprojx_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 
     <AdditionalIncludeDirectories>..\..\Win32;..\..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 
    </ClCompile> 
    <Link> 
     <SubSystem>Windows</SubSystem> 
     <GenerateDebugInformation>true</GenerateDebugInformation> 
     <EnableCOMDATFolding>true</EnableCOMDATFolding> 
     <OptimizeReferences>true</OptimizeReferences> 
     <AdditionalLibraryDirectories>..\..\..\..\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> 
     <AdditionalDependencies>libdirect.lib;%(AdditionalDependencies)</AdditionalDependencies> 
    </Link> 
    </ItemDefinitionGroup> 
    <ItemGroup> 
    <ClCompile Include="..\..\lib\projx\conf.c" /> 
    <ClCompile Include="..\..\lib\projx\hash.c" /> 
    <ClCompile Include="..\..\lib\projx\init.c" /> 
    <ClCompile Include="..\..\lib\projx\shmalloc.c" /> 
    <ClCompile Include="..\..\lib\projx\shm\fake.c" /> 
    <ClCompile Include="..\..\lib\projx\vector.c" /> 
    <ClCompile Include="dllmain.c" /> 
    </ItemGroup> 
    <ItemGroup> 
    <ClInclude Include="..\..\lib\projx\conf.h" /> 
    <ClInclude Include="..\..\lib\projx\hash.h" /> 
    <ClInclude Include="..\..\lib\projx\shmalloc.h" /> 
    <ClInclude Include="..\..\lib\projx\types.h" /> 
    <ClInclude Include="..\..\lib\projx\vector.h" /> 
    </ItemGroup> 
    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> 
    <ImportGroup Label="ExtensionTargets"> 
    </ImportGroup> 
</Project> 

这是我目前使用的是什么来完成这项工作:

string vcName = Path.GetFileName(textBox1.Text); 
string vcProj = Path.Combine(baseDir, vcName); 

using (XmlReader reader = XmlReader.Create(textBox1.Text)) 
{ 
    XmlWriterSettings settings = new XmlWriterSettings(); 
    settings.ConformanceLevel = ConformanceLevel.Auto; 
    settings.Indent = true; 
    settings.CloseOutput = false; 
    string nameSpace = "http://schemas.microsoft.com/developer/msbuild/2003"; 
    using (XmlWriter writer = XmlWriter.Create(vcProj, settings)) 
    { 

     while (reader.Read()) 
     { 
      switch (reader.NodeType) 
      { 
       case XmlNodeType.Element: 

        if (reader.Name == "ClInclude") 
        { 
         //execute code here- omitted for example 
         writer.WriteStartElement(reader.Name, nameSpace); 
         writer.WriteAttributeString("Include", "include/" + filename); 
         writer.WriteEndElement(); 

        } 
        else if (reader.Name == "ClCompile" && reader.HasAttributes) 
        { 
         //execute code here- omitted for example 
         writer.WriteStartElement(reader.Name, nameSpace); 
         writer.WriteAttributeString("Include", "src/" + filename); 
         writer.WriteEndElement(); 

        } 
        else 
        { 
         writer.WriteStartElement(reader.Name, nameSpace); 
         writer.WriteAttributes(reader, true); 
        } 

        break; 

       case XmlNodeType.Text: 
        writer.WriteString(reader.Value); 
        break; 
       case XmlNodeType.XmlDeclaration: 
       case XmlNodeType.ProcessingInstruction: 
        writer.WriteProcessingInstruction(reader.Name, reader.Value); 
        break; 
       case XmlNodeType.Comment: 
        writer.WriteComment(reader.Value); 
        break; 
       case XmlNodeType.Attribute: 
        writer.WriteAttributes(reader, true); 
        break; 
       case XmlNodeType.EntityReference: 
        writer.WriteEntityRef(reader.Value); 
        break; 
       case XmlNodeType.EndElement: 
        writer.WriteFullEndElement(); 
        break; 

       } 
     } 

    } 

回答

0

如果你想使用LINQ到XML为目的,那么你的代码可以是这样的:

var input = @"d:\temp\in.xml"; 
var output = @"d:\temp\out.xml"; 

try 
{   
    // load original file 
    var xmlDocument = XDocument.Load(input); 
    // don't forget to take the namespace, otherwise LINQ will not find the elements 
    XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003"; 
    // finder helper 
    Func<string, IEnumerable<XElement>> getElements = elementName => 
     // find all elements of type ItemGroup 
     // that contain elements of the given type (here ClInclude or ClCompile) 
     xmlDocument.Root.Elements(ns + "ItemGroup").Elements(ns + elementName); 
    // find elements: ClInclude 
    var clInputs = getElements("ClInclude"); 
    foreach (var clInput in clInputs) 
    { 
     // fetch attribute 
     var inputAttribute = clInput.Attributes("Include"); 
     // take first and modify it 
     inputAttribute.ElementAt(0).Value = "some new value"; 
    } 
    // find elements: ClCompile 
    var clCompiles = getElements("ClCompile"); 
    foreach (var clCompile in clCompiles) 
    { 
     // fetch attribute 
     var compileAttribute = clCompile.Attributes("Include"); 
     // take first and modify it 
     compileAttribute.ElementAt(0).Value = "some other value"; 
    } 
    // save modified file under new name 
    xmlDocument.Save(output); 
} 
catch (Exception ex) 
{ 
    Console.WriteLine(ex.Message); 
} 

修改的部分,在新的输出看起来是这样的:

<ItemGroup> 
    <ClCompile Include="some other value" /> 
    <ClCompile Include="some other value" /> 
    ... 
    <ClCompile Include="some other value" /> 
</ItemGroup> 
<ItemGroup> 
    <ClInclude Include="some new value" /> 
    ... 
    <ClInclude Include="some new value" /> 
</ItemGroup> 

更多有关LINQ to XML的信息可以在at MSDN找到。

+0

它比我的尝试更轻,而且完美无缺!我非常感谢帮助。在此之前,我并没有真正想过很多关于LINQ的内容,因为很多的语法看起来都很混乱和不合适。这个解决方案表明它不一定是。现在我知道这是力量,接下来要学什么。再次感谢。 – user1632018

+0

我很高兴,答案有帮助。 – pasty

0

很抱歉,但你为什么不能使用新的东西,微软推荐使用?我给你一个例子。添加

using System.IO;
using System.Xml.Linq;

比方说,你有一个XML文件

<?xml version="1.0" encoding="utf-8" ?> 
<Root> 
    <Employee> 
     <Name> 
      John 
     </Name> 
     <Last> 
      Smith 
     </Last> 
     <Email> 
      [email protected] 
     </Email> 
    </Employee> 
    <Employee> 
     <Name> 
      Danial 
     </Name> 
     <Last> 
      Black 
     </Last> 
     <Email> 
      [email protected] 
     </Email> 
    </Employee> 
    <Employee> 
     <Name> 
      Marry 
     </Name> 
     <Last> 
      Sweet 
     </Last> 
     <Email> 
      [email protected] 
     </Email> 
    </Employee> 
</Root> 

而且要修改姓名中的每个员工

XDocument xDoc = XDocument.Load(@"C:\example.xml"); 

xDoc.Descendants(XName.Get("Employee")).ToList().ForEach(x => 
     { 
      string name = x.Element(XName.Get("Name")).Value; 
      x.Element(XName.Get("Name")).Value = name + " Junior"; 

     }); 

xDoc.Save(@"C:\result.xml"); 

而这一切!

+0

感谢您的回答。我想使用Linq到XML,但我似乎无法得到您的答案工作。我将添加一个XML文件的例子。 – user1632018

+0

我修改了我的问题以包含我试图解析的XML样本,以及更新的读取器和写入器代码。我想摆脱读者作家代码,并采用你的方法。你能帮我吗? – user1632018

0

好你忘记了命名空间

本例中使用你的XML

  XElement xElement = XElement.Load(@"C:\target.xml"); 
      string ns = xElement.Name.Namespace.NamespaceName; 

      xElement.Descendants(XName.Get("ClCompile", ns)).ToList().ForEach(x => 
      { 
       XAttribute xAttr = x.Attribute(XName.Get("Include")); 

       if (xAttr != null) 
       { 
        string name = xAttr.Value; 
        xAttr.Value = name + "?modified"; 
       } 

      }); 


      xElement.Descendants(XName.Get("ClInclude", ns)).ToList().ForEach(x => 
      { 
       XAttribute xAttr = x.Attribute(XName.Get("Include")); 

       if (xAttr != null) 
       { 
        string name = xAttr.Value; 
        xAttr.Value = name + "?included"; 
       } 
      }); 

      xElement.Save(@"C:\result.xml"); 

所以我只需要添加一个字符串,有包括属性标签!

相关问题