c# linq 更改包含 xml 标签的 xml 元素的值
c# linq change the value of xml element which contains xml tags
我测试了以下来源 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>
我想要 copy/clone 完整标签(房间 ID="R1")并粘贴为楼层中的最后一个房间。同时我想将 (room id="R1") 的标签值更改为 "Whatever" 并将 (room)-Tag 中的 (socket id) 更改为 "new room"
最后想得到下面的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");
}
}
}
如何使用 linq 在 c# 中更改值,而不删除嵌入的 xml 结构?
感谢您的提示
你select那排
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>
您必须将 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>
我测试了以下来源 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>
我想要 copy/clone 完整标签(房间 ID="R1")并粘贴为楼层中的最后一个房间。同时我想将 (room id="R1") 的标签值更改为 "Whatever" 并将 (room)-Tag 中的 (socket id) 更改为 "new room"
最后想得到下面的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");
}
}
}
如何使用 linq 在 c# 中更改值,而不删除嵌入的 xml 结构?
感谢您的提示
你select那排
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>
您必须将 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>