XmlReader - мне нужно отредактировать элемент и создать новый - PullRequest
7 голосов
/ 01 октября 2009

Я переопределяю метод, в который передается 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;
}

Ответы [ 5 ]

13 голосов
/ 19 февраля 2010

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, но я считаю, что это намного проще.

[EDIT]

Пример того, как вы открываете два потока одновременно, может быть примерно таким:

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 голос
/ 01 октября 2009

Я исправил это с помощью следующей кодировки клейкой ленты

    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 голос
/ 01 октября 2009

Вы не можете легко сделать это с XmlReader - по крайней мере, без чтения всего XML-документа из считывателя, срывания его с последующим созданием нового XmlReader из результата. Однако это лишает смысла использование XmlReader, а именно возможность потоковой передачи больших документов.

Вы можете потенциально получить из XmlReader, перенаправляя большинство вызовов методов существующему считывателю, но перехватывая их, где это необходимо, для добавления дополнительных атрибутов и т. Д. ... но я подозреваю, что код будет действительно довольно сложным хрупкий.

0 голосов
/ 18 мая 2010
        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

0 голосов
/ 19 февраля 2010

Я бы предпочел загрузить 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 пробельные символы сохранялись неправильно, иногда это может раздражать

...