Лучший способ изменить значение элемента в C # - PullRequest
14 голосов
/ 13 февраля 2009

Я пытаюсь найти лучший способ изменить значение элемента в XML.

<MyXmlType>
   <MyXmlElement>Value</MyXmlElement>
</MyXmlType>

Какой самый простой и / или лучший способ изменить «Значение» в C #?

Я посмотрел на XMLDocument, и он вызовет загрузку всего XML-документа в память. Не могли бы вы сделать это безопасно с XMLReader. Проблема заключается в изменении значения, и его возвращение кажется интересной загадкой.

Приветствия: D

Ответы [ 9 ]

32 голосов
/ 13 февраля 2009

Вы можете использовать пространство имен System.Xml.Linq для простоты чтения кода. Это загрузит полный файл в память.

XDocument xdoc = XDocument.Load("file.xml");
var element = xdoc.Elements("MyXmlElement").Single();
element.Value = "foo";
xdoc.Save("file.xml");
5 голосов
/ 13 февраля 2009

РЕДАКТИРОВАТЬ: не видел ваше предложение о XmlDocument. XmlReader делает именно это. Вы не можете редактировать XML-файлы с этим классом.

Вы хотите XmlWriter. Однако, если это все еще полезно, вот код для XmlDocument.

private void changeXMLVal(string element, string value)
{
    try
    {
        string fileLoc = "PATH_TO_XML_FILE";
        XmlDocument doc = new XmlDocument();
        doc.Load(fileLoc);
        XmlNode node = doc.SelectSingleNode("/MyXmlType/" + element);
        if (node != null)
        {
            node.InnerText = value;
        }
        else
        {
            XmlNode root = doc.DocumentElement;
            XmlElement elem;
            elem = doc.CreateElement(element);
            elem.InnerText = value;
            root.AppendChild(elem);
        }
        doc.Save(fileLoc);
        doc = null;
    }
    catch (Exception)
    {
        /*
         * Possible Exceptions:
         *  System.ArgumentException
         *  System.ArgumentNullException
         *  System.InvalidOperationException
         *  System.IO.DirectoryNotFoundException
         *  System.IO.FileNotFoundException
         *  System.IO.IOException
         *  System.IO.PathTooLongException
         *  System.NotSupportedException
         *  System.Security.SecurityException
         *  System.UnauthorizedAccessException
         *  System.UriFormatException
         *  System.Xml.XmlException
         *  System.Xml.XPath.XPathException
        */
    }
}
2 голосов
/ 20 сентября 2012

При этом используется старый файл и создается новый с обновленным значением. Он выдаст исключение, если не может найти элемент

{
    XDocument newSettingFile =  new XDocument(settingFile);
    //Root element
    var newSetting = newSettingFile.Element("MyXmlType");
    //Update childelement with new value
    newSetting.Element("MyXmlElement").Value = "NewValue";   
    return newSettingFile;
}
2 голосов
/ 13 февраля 2009

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

XmlReader предположительно является улучшением по сравнению с API синтаксического анализатора SAX XML, который появился в мире Java, но который стал стандартом де-факто в отрасли (за пределами Microsoft).

Если вы просто хотите быстро выполнить работу, для этой цели существует XmlTextReader (в .NET).

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

Пожалуйста, ознакомьтесь с моим ответом о SAX здесь, чтобы получить список ресурсов SAX и действительно креативную .NET XML-парсер , которая использует XmlTextReader в качестве основы: SAX против XmlTextReader - SAX в C #

2 голосов
/ 13 февраля 2009

Задумывались ли вы об использовании Linq to XML? (если вы используете .Net 3.0 +)

public static XElement ChangeValue(string xmlSnippet, 
    string nodeName,
    string newValue)
{
    XElement snippet = XElement.Parse(xmlSnippet);
    if (snippet != null)
    {
        snippet.Element(nodeName).Value = newValue;
    }
    return snippet;
}

Я предполагаю, что XElement будет работать лучше, чем XmlDocument (хотя и не уверен), базовый объект для XElement - XObject, и да, ему придется загрузить весь документ.

2 голосов
/ 13 февраля 2009

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

Честно говоря, я немного удивлен, что ваш XML-файл настолько велик, что вы беспокоитесь о потреблении памяти ... не говоря уже о том, что это никогда не было проблемой. Без дополнительной информации я не могу сказать, что ваш гипотетический XML-файл не является 50-гигабайтным, но во многих случаях загрузка файлов, которые кажутся достаточно большими в память, чтобы манипулировать ими, не так сложна, как вы думаете.

1 голос
/ 15 августа 2015

Я провел несколько тестов для документа размером 10,6 К. Синтаксический анализ XmlDocument всегда выполняется быстрее, чем запрос Linq, примерно на 50%.

       var stopwatch2 = Stopwatch.StartNew();
        XmlDocument xd = new XmlDocument();
        xd.LoadXml(instanceXML);
        XmlNode node = xd.SelectSingleNode("//figures/figure[@id='" + stepId + "']/properties/property[@name='" + fieldData + "']");
            node.InnerXml = "<![CDATA[ " + valData + " ]]>";  
        stopwatch2.Stop();
        var xmlDocTicks = stopwatch2.ElapsedTicks;

        Stopwatch stopwatch1 = Stopwatch.StartNew(); 
        XDocument doc = XDocument.Parse(instanceXML);
        XElement prop =
        (from el in doc.Descendants("figure")
         where (string)el.Attribute("id") == stepId
            select el).FirstOrDefault();
        prop.Value = valData;
        stopwatch1.Stop();
        var linqTicks = stopwatch1.ElapsedTicks;

Результаты выглядят следующим образом (xmlDocTicks, linqTicks):

  • run1: (1258,1581)
  • RUN2: (2667,3463)
  • RUN3: (1416,2626)
  • run4: (1231,2383)
  • ср .: (1643,2513)
1 голос
/ 07 октября 2011
using System;
using System.Xml;
using System.Linq;
using System.Xml.Linq;

namespace ReandAndWriteXML
{
    class MainClass
    {
        public static void Main (string[] args)
        {
            XDocument xdoc = XDocument.Load(@"file.xml");
            var element = xdoc.Root.Elements("MyXmlElement").Single();
            element.Value = "This wasn't nearly as hard as the internet tried to make it!";
            xdoc.Save(@"file.xml");
        }
    }
}

Это очень похоже на пример Бена Робина, за исключением того, что он работает (хотя его тоже, теперь, когда он отредактирован) И я даже дал вам инструкции по использованию!

0 голосов
/ 04 августа 2018

Загрузить и сохранить

public XDocument XDocument { get; set; }
    private async Task OpenResWFileAsync()
    {
        List<XElement> dataElements;
        var reswFile = await StorageHelper.PickSingleFileAsync(".resw");
        if (reswFile == null) return;
        using (Stream fileStream = await reswFile.OpenStreamForReadAsync())
        {
            this.XDocument = XDocument.Load(fileStream);
            dataElements = this.XDocument.Root.Elements("data").ToList();
            this.DataElements = dataElements;
        }
    }
    #region
    private List<string> GetValues()
    {
        if (this.XDocument == null) return new List<string>();
        return this.XDocument.Root.Elements("data").Select(e => e.Attribute("name").Value).ToList();

    }
    public void ChangeValue(string resourceKey, string newValue)
    {
        if (this.DataElements == null) return;
        var element = this.DataElements.Where(e => e.Name == resourceKey).Single();
        element.Value = newValue;
    }
    #endregion
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...