Замените значение, полагаясь на существующее значение в файле XML.

avatar
hamed abdulhadi
8 апреля 2018 в 05:32
61
2
1

Это пример файла XML:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string name="app_name">Automation Test</string>
  <string name="current_data_state_incoming_call">Incoming Call</string>
  <string name="current_data_state_outgoing_call">Outgoing Call</string>
  <string name="current_data_state_missed_call">Missed Call</string>
  <string name="current_data_state_photo">Photo</string>
  <string name="current_data_state_video">Video</string>
  <string name="current_data_state_mp3">MP3</string>
  <string name="current_data_state_voice_memo">Voice Memo</string>
  <string name="current_data_state_phone_book">Phone Book</string>
  <string name="current_data_state_phone_booksim">Phone Book(SIM)</string>
  <string name="current_data_state_etc">Etc</string>
  <string name="current_data_state_schedule">S Planner</string>

</resources>

У меня есть большой файл XML, и я хочу заменить значения в элементах в зависимости от их исходного значения.

Например, я хочу заменить "Исходящий вызов" другим словом. Я попробовал этот код:

XmlDocument xdoc = new XmlDocument();
xdoc.Load("strings.xml");

XmlElement root = xdoc.DocumentElement;
XmlNodeList elemList = root.GetElementsByTagName("string");

for (int i = 0; i < elemList.Count; i++)
{
    xdoc.Save("strings.xml");

    if (elemList[i].InnerText == "Incoming Call")
    {
        // xdoc.LoadXml(File.ReadAllText("strings.xml").Replace(elemList[i].InnerText, "صندوق"));
        //   MessageBox.Show(elemList[i].InnerText);
        elemList[i].SelectSingleNode("resources/string").InnerText="مكالمات قادمة";        
        xdoc.Save("strings.xml");
    }
}

и этот код

XmlDocument xdoc = new XmlDocument();
xdoc.Load("strings.xml");

XmlNodeList aNodes = xdoc.SelectNodes("resources/string");
foreach (XmlNode node in aNodes)
{
    XmlNode child1 = node.SelectSingleNode("string");
    if(child1.InnerText == "Incoming Call")
    {
        child1.InnerText = "اتصالات قادمة";
    }
}
xdoc.Save("strings.xml");

Я не могу заменить значение.

=================================== Спасибо, я решаю свою проблему

var root2 = new XmlDocument();
        root2.Load("strings.xml");
        var root = new XmlDocument();
        root.Load("strings2.xml");

        foreach (XmlNode e1 in root2.GetElementsByTagName("string"))
        {
            string a = e1.Attributes["name"].Value;
            foreach (XmlNode ee in root.GetElementsByTagName("string"))

            {
                string b = ee.Attributes["name"].Value;
                if (a == b)
                {
                    e1.FirstChild.Value = ee.FirstChild.Value;
                }
            }



        }
        root.Save("strings.xml");
Источник
Gabriel
8 апреля 2018 в 05:45
1

Вы должны размещать свой код в виде текста, а не изображений. И помните о форматировании.

hamed abdulhadi
8 апреля 2018 в 07:31
0

я редактирую это спасибо

Jon Skeet
8 апреля 2018 в 08:20
0

Есть ли причина, по которой вам нужно использовать XmlDocument вместо LINQ to XML? Последнее сделает его намного проще.

Gabriel
8 апреля 2018 в 23:59
0

@hamedabdulhadi Спасибо, что последовали моему совету. Я проголосовал за ваш вопрос.

Ответы (2)

avatar
Jon Skeet
8 апреля 2018 в 09:13
1

Для этого я бы использовал LINQ to XML. Это делает все намного проще, чем XmlDocument. Вот полный пример выполнения замены (загрузка input.xml и запись output.xml):

using System;
using System.Linq;
using System.Xml.Linq;

class Test
{
    static void Main()
    {
        XDocument doc = XDocument.Load("input.xml");
        ReplaceValue(doc, "Outgoing Call", "Other value");
        doc.Save("output.xml");
    }

    static void ReplaceValue(XDocument doc, string original, string replacement)
    {
        foreach (var element in doc.Descendants("string").Where(x => x.Value == original))
        {
            element.Value = replacement;
        }
    }
}

Можно легко изменить метод так, чтобы он генерировал исключение, если он не найдет значение, которое вы пытаетесь заменить, или если он найдет более одного элемента.

В качестве альтернативы замене на value можно было бы заменить атрибутом name, что было бы тривиальным изменением:

static void ReplaceNamedValue(XDocument doc, string name, string replacement)
{
    foreach (var element in doc.Descendants("string")
        .Where(x => (string) x.Attribute("name") == name))
    {
        element.Value = replacement;
    }
}

Тогда вы бы назвали это так:

ReplaceNamedValue(doc, "current_data_state_outgoing_call", "Other value");
avatar
jdweng
8 апреля 2018 в 08:33
-1

Возможно, вы захотите создать файл в формате xml на лету вместо замены. Я предпочитаю использовать более новую сетевую библиотеку xml linq (XDocument), а не более старую версию XmlDocument. Вот пример кода, который я бы использовал:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {

        static void Main(string[] args)
        {
            string ident = "<?xml version=\"1.0\" encoding=\"utf-8\"?><resources></resources>";
            XDocument doc = XDocument.Parse(ident);

            XElement resources = doc.Root;

            resources.Add(new XElement("string", new object[] {
                new XAttribute("name","app_name"),
                "Automation Test"
            }));

            resources.Add(new XElement("string", new object[] {
                new XAttribute("name","current_data_state_incoming_call"),
                "مكالمات قادمة"
            }));
        }
    }
}

Вот код замены

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {

            XDocument doc = XDocument.Load(FILENAME);
            XElement resource = doc.Root;

            Dictionary<string, XElement> dict = resource.Elements()
                .GroupBy(x => (string)x.Attribute("name"), y => y)
                .ToDictionary(x => x.Key, y => y.FirstOrDefault());

            if(dict.ContainsKey("app_name"))
            {
                dict["app_name"].SetValue("Automation Test");
            }

            if (dict.ContainsKey("current_data_state_incoming_call"))
            {
                dict["current_data_state_incoming_call"].SetValue("مكالمات قادمة");
            }

        }
    }
}
Jon Skeet
8 апреля 2018 в 08:43
0

Это не отвечает на вопрос - вопрос конкретно о том, «как заменить элементы в существующем файле», поэтому ответ, который этого не делает, бесполезен, IMO.

hamed abdulhadi
8 апреля 2018 в 08:47
0

да как заменить элементы в существующем файле?

jdweng
8 апреля 2018 в 08:49
0

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

Jon Skeet
8 апреля 2018 в 09:09
0

Хотя я согласен с тем, что иногда первоначальный подход не самый лучший, я не вижу признаков того, что здесь дело обстоит именно так. В каком контексте вы должны категорично заявить "В таком случае лучше создать"? Мне кажется, ты слишком много на себя берешь. Также обратите внимание, что ваш новый пример, в котором используется атрибут name, не заменяется так, как хотел OP, то есть на value.

jdweng
8 апреля 2018 в 11:28
0

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

Jon Skeet
8 апреля 2018 в 15:14
0

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

jdweng
8 апреля 2018 в 16:16
0

Совершенно с вами не согласен. Замена значений не очень эффективна. Алгоритм замены занимает N * N/2, потому что вам нужно искать в файле, чтобы найти элемент для замены. Прямая запись занимает всего N. Очень плохая техника для замены.