2015-08-11 8 views
2

Я протестирована со следующим исходным XML-файломC# LINQ изменить значение XML-элемент, который содержит XML-тег

<?xml version="1.0" encoding="utf-8" standalone="no"?> 
<root> 
    <key name="some text" id="1"/> 
    <key name="some text" id="2"/> 
    <house id="H1"> 
     <floor id="F1"> 
      <room id="R1">Child1<electrics><socket id="C1S1"/></electrics></room> 
      <room id="R2">Child2<electrics><socket id="C2S1"/></electrics></room> 
     </floor> 
    </house> 
</root> 

Я хотел бы копировать/клонировать полный тег (номер ID = «R1») и пасты как последняя комната в полу. В то же время я хочу изменить значение тега (номер id = «R1») на «Независимо» и (идентификатор гнезда) в пределах (комнаты) -Tag до «новой комнаты»

Окончание Я хочу получить следующую xml-структуру

<?xml version="1.0" encoding="utf-8"?> 
<root> 
    <key name="some text" id="1" /> 
    <key name="some text" id="2" /> 
    <house id="H1"> 
    <floor id="F1"> 
     <room id="R1">Child1<electrics><socket id="C1S1" /></electrics></room> 
     <room id="R2">Child2<electrics><socket id="C2S1" /></electrics></room> 
     <room id="R1">Whatever<electrics><socket id="new room" /></electrics></room> 
    </floor> 
    </house> 
</root> 

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

Вот мой C# код

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
using System.Diagnostics; 
using System.Xml.Linq; 

namespace linqxmlTester 
{ 
    public partial class Form1 : Form 
    { 
     private XElement xmlDoc; 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void btnStart_Click(object sender, EventArgs e) 
     { 

      xmlDoc = XElement.Load("house.xml"); 

      // Select rooms to clone I realy only want to selekt one room, but I have to go over rooms 
      IEnumerable<XElement> newRoom = from rooms in xmlDoc.Element ("house") 
                   .Element ("floor") 
                   .Elements("room") 

                where rooms.ToString().IndexOf("C1S1") > 0 

                select rooms; 
      // I've selected realy one room in rooms with the following I clone beheind last room 
      xmlDoc.Element ("house") 
        .Element ("floor") 
        .Elements("room").Last() 
        .AddAfterSelf(newRoom.First()); // there is only one 

      // This worked :-) 

      //But now I want to change socket id value (="C1S1") to something new 
      //I select my last created room 

      XElement newRoom1 = xmlDoc.Element("house") 
             .Element("floor") 
             .Elements("room").Last(); 

      //within the newRoom1 I search for the attribute id 

      foreach (var r in newRoom1.Elements("electrics").Elements("socket")) 
      { 
       Debug.WriteLine("aktValue " + r.Attribute("id").Value); 
       r.Attribute("id").Value = "new room"; 
       Debug.WriteLine("newValue " + r.Attribute("id").Value); 
      } 

      // this is working too :-) 

      // Now I only still have to change the value of my newroom 
      // it should be the following code 

      Debug.WriteLine("OldValue " + newRoom1.Value); // prints only the value without the embeded xml tags 

      newRoom1.SetValue("Whatever"); // this kills the complete xml structure with is embede at the side of the value 

      Debug.WriteLine("NewValue " + newRoom1.Value); // prints only the newvalue without the embeded xml tags 

      xmlDoc.Save("housenew.xml"); 
     } 
} 
} 

Как я могу изменить значение в C# с помощью LINQ, без удаления структуры XML поместить его?

Спасибо за ваши советы

ответ

1

Вам нужно будет увидеть ваш элемент room как узел дерева. Все, что ниже этого, также является узлом, поэтому на самом деле Child1 является узлом (текст), а electrics является узлом (элементом).

Визуально представлены:

* Element: room (with attribute id) 
|- Text: Child1 
|- Element: electrics 
    |- Element: socket (with attribute id) 

Так, чтобы добраться до этого текстового узла (Child1), просто измените первый подузла room, как например:

newRoom1.Nodes().First().ReplaceWith("Whatever"); 

Если вы хотите изменить .Value из комнату, вы замените все поддерево room.

Я бы избежал такого рода структуры, хотя, если это возможно. Измените значение «Child1» так, чтобы оно было либо атрибутом комнаты (предпочтительным), либо обернуло его в узле так, чтобы <room id="1"><description>Child1</description></room>

+0

Спасибо. ReplaceWith решил мою проблему. Мой пример structur был просто для упрощения, где мой проблема была. На самом деле я пытаюсь редактировать графический файл, созданный yed, где я столкнулся с гораздо большими трудностями. – gequest

0

Вы выбираете строку, так

class Program 
 
    { 
 
     static void Main(string[] args) 
 
     { 
 
      string input = 
 
       "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>" + 
 
       "<root>" + 
 
        "<key name=\"some text\" id=\"1\"/>" + 
 
        "<key name=\"some text\" id=\"2\"/>" + 
 
        "<house id=\"H1\">" + 
 
         "<floor id=\"F1\">" + 
 
          "<room id=\"R1\">Child1<electrics><socket id=\"C1S1\"/></electrics></room>" + 
 
          "<room id=\"R2\">Child2<electrics><socket id=\"C2S1\"/></electrics></room>" + 
 
         "</floor>" + 
 
        "</house>" + 
 
       "</root>"; 
 

 
      XElement xmlDoc = XElement.Parse(input); 
 
      XElement floor = xmlDoc.Descendants("floor").FirstOrDefault(); 
 
      XElement newR1 = new XElement(floor.Elements("room").Where(x => x.Attribute("id").Value == "R1").FirstOrDefault()); 
 
      XAttribute socket = newR1.Element("electrics").Element("socket").Attribute("id"); 
 
      socket.Value = "new room"; 
 
      floor.Add(newR1); 
 
     } 
 
    } 
 
}

Это XML результатам

<root> 
 
    <key name="some text" id="1" /> 
 
    <key name="some text" id="2" /> 
 
    <house id="H1"> 
 
    <floor id="F1"> 
 
     <room id="R1">Child1<electrics><socket id="C1S1" /></electrics></room> 
 
     <room id="R2">Child2<electrics><socket id="C2S1" /></electrics></room> 
 
     <room id="R1">Child1<electrics><socket id="new room" /></electrics></room> 
 
    </floor> 
 
    </house> 
 
</root>

+0

Выбор для комнаты в этом решении намного короче, чем мой. Но все же невозможно изменить значение тега newR1. Если я добавлю newR1.SetValue («Независимо»); до пола.добавить всю структуру () будет удалена. – gequest

+0

Я опубликовал результаты XML, которые именно вы ищете. – jdweng

+0

Это почти решение, которое я искал. У меня были проблемы с изменением значения второго «Child1» на «Anything». Это разрешено с помощью newR1.Nodes(). First(). ReplaceWith («Неважно»); Но вы помогли мне с другим подходом, используя «.Where (x => ......) Большое спасибо за это. – gequest

Смежные вопросы