2009-10-01 81 views
6

我重写了一个方法,它传递了一个XmlReader,我需要找到一个特定的元素,添加一个属性,然后创建一个新的XmlReader或者只是替换现有的修改后的内容。我正在使用C#4.0XmlReader - 我需要编辑一个元素并产生一个新的元素

我调查了使用XElement(Linq)但我似乎无法操纵现有的元素并添加属性和值。

我知道的XmlWriter具有WriteAttributeString这将是非常美妙的,但我又是不知道这一切是如何结合在一起

我希望能够做这样的事情---这是伪代码!

public XmlReader DoSomethingWonderful(XmlReader reader) 
{ 
    Element element = reader.GetElement("Test"); 
    element.SetAttribute("TestAttribute","This is a test"); 
    reader.UpdateElement(element); 
    return reader; 
} 

回答

11

的XmlReader /写入器顺序访问流。你将不得不在一端阅读,处理你想要的流,并把它写在另一端。好处是你不需要将整个东西读入内存中并构建一个DOM,这就是你使用任何基于XmlDocument的方法所得到的结果。

这个方法应该让你开始:

private static void PostProcess(Stream inStream, Stream outStream) 
{ 
    var settings = new XmlWriterSettings() { Indent = true, IndentChars = " " }; 

    using (var reader = XmlReader.Create(inStream)) 
    using (var writer = XmlWriter.Create(outStream, settings)) { 
     while (reader.Read()) { 
      switch (reader.NodeType) { 
       case XmlNodeType.Element: 
        writer.WriteStartElement(reader.Prefix, reader.Name, reader.NamespaceURI); 
        writer.WriteAttributes(reader, true); 

        // 
        // check if this is the node you want, inject attributes here. 
        // 

        if (reader.IsEmptyElement) { 
         writer.WriteEndElement(); 
        } 
        break; 

       case XmlNodeType.Text: 
        writer.WriteString(reader.Value); 
        break; 

       case XmlNodeType.EndElement: 
        writer.WriteFullEndElement(); 
        break; 

       case XmlNodeType.XmlDeclaration: 
       case XmlNodeType.ProcessingInstruction: 
        writer.WriteProcessingInstruction(reader.Name, reader.Value); 
        break; 

       case XmlNodeType.SignificantWhitespace: 
        writer.WriteWhitespace(reader.Value); 
        break; 
      } 
     } 
    } 
} 

这是不是很派生自己的XmlWriter一样干净,但我发现它更容易。

[编辑]

的你会如何同时打开两个流可能是这样一个例子:

using (FileStream readStream = new FileStream(@"c:\myFile.xml", FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write)) { 
    using (FileStream writeStream = new FileStream(@"c:\myFile.xml", FileMode.OpenOrCreate, FileAccess.Write)) { 
    PostProcess(readStream, writeStream); 
    } 
} 
1

你不能简单的用XmlReader做到这一点 - 至少,不是没有从读者阅读整个XML文档中,它把玩,然后创建从结果新XmlReader。这虽然破坏了很多使用XmlReader的要点 - 即流式传输大型文档的能力。

你可以潜在XmlReader派生,转发最多方法调用现有的读者,但他们拦截酌情添加额外的属性等等...但我怀疑的代码将是非常非常复杂和脆弱。

+0

感谢您的答复,我认为(希望)这将是很好的简单操作。我不能成为唯一一个想将XML读入特定元素的人,编辑它然后输出更改后的结果。 - 如果你今天在阅读中听到比平常更多的脏话......这是我的! – 2009-10-01 08:06:52

+0

@Phill:很容易做到这一点,只是没有以流的方式我很害怕:( – 2009-10-01 08:14:52

+0

子类化'XmlReader'(实际上你会'XmlTextReader'的子类,除非你觉得实现很多抽象方法)是一个有趣的挑战 – 2009-10-01 19:28:42

1

我固定它使用下面的胶带编码

public XmlReader FixUpReader(XmlReader reader) 
    { 
     reader.MoveToContent(); 

     string xml = reader.ReadOuterXml(); 

     string dslVersion = GetDSLVersion(); 
     string Id = GetID(); 

     string processedValue = string.Format("<ExampleElement dslVersion=\"{1}\" Id=\"{2}\" ", dslVersion, Id); 
     xml = xml.Replace("<ExampleElement ", processedValue); 
     MemoryStream ms = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(xml)); 
     XmlReaderSettings settings = new XmlReaderSettings(); 

     XmlReader myReader = XmlReader.Create(ms); 
     myReader.MoveToContent(); 
     return myReader; 
    } 

我觉得脏了做这种方式,但它是工作....

+1

我不会确定它是否正常工作,您返回的读者不会去能够在此元素之后移动到元素,因为该元素(实际上是原始阅读器正在处理的所有XML文档的其余部分)不在其支持流中。 – 2009-10-01 19:31:50

0

我宁愿将XML加载到XmlDocument对象并使用Attributes集合来修改该值并调用Save方法来更新此值。下面的代码适用于我。

public static void WriteElementValue (string sName, string element, string value) 
{ 
    try 
    { 
    var node = String.Format("//elements/element[@name='{0}']", sName); 
    var doc = new XmlDocument { PreserveWhitespace = true }; 
    doc.Load(configurationFileName); 

    var nodeObject = doc.SelectSingleNode(node); 

    if (nodeObject == null) 
     throw new XmlException(String.Format("{0} path does not found any matching 
     node", node)); 

    var elementObject = nodeObject[element]; 

    if (elementObject != null) 
    { 
     elementObject.Attributes["value"].Value = value; 
    } 

    doc.Save(configurationFileName); 
} 
catch (Exception ex) 
{ 
    throw new ExitLevelException(ex, false); 
} 

}

当您使用的XmlWriter或XmlSerializer的的空白字符没有被正确保存,我也观察到,这可能是恼人有时

-2
 string newvalue = "10"; 
     string presentvalue = ""; 
     string newstr = ""; 
     XmlReader xmlr = XmlReader.Create(new StringReader(str)); 

     while (xmlr.Read()) 
     { 
      if (xmlr.NodeType == XmlNodeType.Element) 
      { 
       if (xmlr.Name == "priority") 
       { 
        presentvalue = xmlr.ReadElementContentAsString(); 
        newstr = str.Replace(presentvalue, newvalue); 
       } 
      } 

     } 

//可中newstr写回文件。 ..这是编辑xml

相关问题