2013-10-25 31 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"); 

所以我只需要添加一個字符串,有包括屬性標籤!

相關問題