读取XML文件然后写入重复版本

时间:2013-10-25 04:40:44

标签: c# .net xml visual-studio-2010 xmlreader

我正在尝试读取XML文件,并根据我想要执行某些代码的元素的值,然后将值替换为生成的代码,然后将文件保存到新位置。

我目前正在这样做的方式非常冗长且不准确,并且变成了一个大麻烦。我想要做的是修改“ClInclude”和“ClCompile”元素。当找到它们时,我想执行一些代码,然后用新的代码替换当前值而不是保存它们。我更喜欢使用linq to xml方法而不是我的XML reader和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;

                }
        }

    }

3 个答案:

答案 0 :(得分:0)

抱歉,为什么你不能使用微软推荐使用的新STUFF?我举个例子。添加

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

假设你有一个xml文件

<?xml version="1.0" encoding="utf-8" ?> 
<Root>
    <Employee>
        <Name>
            John
        </Name>
        <Last>
            Smith
        </Last>
        <Email>
            js@gmail.com
        </Email>
    </Employee>
    <Employee>
        <Name>
            Danial
        </Name>
        <Last>
            Black
        </Last>
        <Email>
            db@gmail.com
        </Email>
    </Employee>
    <Employee>
        <Name>
            Marry
        </Name>
        <Last>
            Sweet
        </Last>
        <Email>
            ms@gmail.com
        </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");

就是这样!

答案 1 :(得分:0)

如果您想将LINQ to 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

答案 2 :(得分:0)

好的,你刚忘了Namespace

此示例使用您的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");

所以我只是在具有Include属性的标签上添加一个字符串!