【问题标题】:XmlReader - I need to edit an element and produce a new oneXmlReader - 我需要编辑一个元素并生成一个新元素
【发布时间】:2010-12-02 21:55:03
【问题描述】:

我正在重写一个传入 XmlReader 的方法,我需要找到一个特定元素,添加一个属性,然后创建一个新的 XmlReader 或将现有的 XmlReader 替换为修改后的内容。我正在使用 C#4.0

我已经使用 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;
}

【问题讨论】:

    标签: c# xml c#-4.0 xmlreader


    【解决方案1】:

    XmlReader/Writer 是顺序访问流。您必须在一端读入,以您想要的方式处理流,然后在另一端写出。优点是您不需要将整个内容读入内存并构建 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);
      }
    }
    

    【讨论】:

      【解决方案2】:

      我使用以下胶带编码修复了它

          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;
          }
      

      我觉得这样做很脏,但它确实有效....

      【讨论】:

      • 我不太确定它是否有效。您返回的阅读器将无法移动到该元素之后的元素,因为该元素(实际上,原始阅读器正在处理的所有其他 XML 文档)不在其支持流中。
      【解决方案3】:

      您不能使用XmlReader 轻松做到这一点——至少,如果不从阅读器中读取整个 XML 文档,对其进行处理,然后从结果中创建一个新的 XmlReader,就不会这样做。不过,这与使用XmlReader 的许多意义相去甚远——即流式传输大型文档的能力。

      你可以可能XmlReader派生,将大多数方法调用转发给现有的阅读器,但在适当的地方拦截它们以添加额外的属性等......但我怀疑代码会非常复杂又脆弱。

      【讨论】:

      • 感谢您的回复,我认为(希望)这是一个不错的简单操作。我不可能是唯一一个想要在 XML 中读取某个元素、对其进行编辑然后输出更改后的结果的人。 - 如果你今天在阅读中听到比平时更多的脏话......那就是我!
      • @Phill:这很容易做到,只是恐怕不是以流的方式:(
      • 子类化XmlReader(实际上你会继承XmlTextReader,除非你想实现很多抽象方法)是一个有趣的挑战。
      • @RobertRossney 不要再使用 XmlTextReader:stackoverflow.com/questions/8096564/xmltextreader-vs-xdocument
      【解决方案4】:

      我宁愿将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 时,空白未正确保留,这有时会很烦人

      【讨论】:

        【解决方案5】:
                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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-16
          • 1970-01-01
          • 2011-08-11
          • 2013-10-11
          • 1970-01-01
          相关资源
          最近更新 更多