XmlReader - I need to edit an element and produce a new one

不打扰是莪最后的温柔 提交于 2019-12-18 07:46:08

问题


I am overriding a method which has an XmlReader being passed in, I need to find a specific element, add an attribute and then either create a new XmlReader or just replace the existing one with the modified content. I am using C#4.0

I have investigated using XElement (Linq) but I can't seem to manipulate an existing element and add an attribute and value.

I know that the XmlWriter has WriteAttributeString which would be fantastic but again I am not sure how it all fits together

I would like to be able to do something like --- This is pseudo-code!

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

回答1:


XmlReader/Writer are sequential access streams. You will have to read in on one end, process the stream how you want, and write it out the other end. The advantage is that you don't need to read the whole thing into memory and build a DOM, which is what you'd get with any XmlDocument-based approach.

This method should get you started:

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

This is not quite as clean as deriving your own XmlWriter, but I find that it's much easier.

[EDIT]

An example of how you would open two streams at once might be something like this:

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:


You can't easily do this with XmlReader - at least, not without reading the whole XML document in from the reader, futzing with it and then creating a new XmlReader from the result. That defeats a lot of the point of using XmlReader though - namely the ability to stream large documents.

You could potentially derive from XmlReader, forwarding most method calls to the existing reader but intercepting them where appropriate to add extra attributes etc... but I suspect that code would be really quite complex and fragile.




回答3:


I fixed it using the following duct tape coding

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

I feel dirty for doing it this way but it is working....




回答4:


I would rather prefer to load the xml into XmlDocument object and use Attributes collection to modify the value and call Save method to update this value. Below code works for me.

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

}

I've also observed when you use XmlWriter or XmlSerializer the whitespaces were not correctly preserved, this could be annoying sometimes




回答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 can be written back to file... that is the edited xml



来源:https://stackoverflow.com/questions/1502450/xmlreader-i-need-to-edit-an-element-and-produce-a-new-one

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!