11

我正在重写一个传入了 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;
}
4

5 回答 5

14

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);
  }
}
于 2010-02-19T12:35:44.083 回答
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;
    }

我觉得这样做很脏,但它正在工作....

于 2009-10-01T10:59:37.780 回答
1

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

于 2010-02-19T11:39:30.220 回答
1

您不能轻易地做到这一点XmlReader——至少,如果不从阅读器中读取整个 XML 文档,对其进行处理,然后XmlReader从结果中创建一个新文档,就不能这样做。但是,这破坏了很多使用点XmlReader- 即流式传输大型文档的能力。

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

于 2009-10-01T07:54:40.947 回答
-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

于 2010-05-18T16:13:55.977 回答