我正在编写一个函数来更新我的XML并遇到一些问题。我希望我可以直接将旧的XElement设置为更新的那个但是在foreach循环中不起作用(尽管应该只是一个查询结果)。我打算对每个字段进行硬编码,但后来决定使用循环。然而,当它击中该部分及其子元素时,它将所有内容作为单个元素读取并将文件弄乱
var myDevice = from c in appDataXml.Descendants("device")
where (string)c.Element("name") == App.CurrentDeviceName
&& (string)c.Element("ip") == App.CurrentIp
select c;
if (myDevice.Any())
{
foreach (XElement device in myDevice)
{
//device.Element("customname").Value = updatedDevice.Element("customname").Value;
for (int a = 0; a < device.Elements().Count(); a++)
{
string field = device.Elements().ElementAt(a).Name.ToString();
device.Element(field).Value = updatedDevice.Element(field).Value;
}
}
}
示例XML
<Devices>
<device>
<name>blah</name>
<customname>custom</customname>
<ip>192.168.1.100</ip>
<port>1000</port>
<sources>
<source>
<code>00</code>
<name>blah2</name>
<hidden>False</hidden>
</source>
<source>
...etc
</sources>
</device>
答案 0 :(得分:1)
你的意思是var myDevice = ... select c;
最多会产生1个元素吗?
如果有,请用.Any()
替换洞foreach()
和.Single()
:
var myDevices = ... select c;
var myDevice = myDevices.Single(); // exception when Count != 1
然后我认为没有理由不这样做:
myDevice.Element("customname").Value = updatedDevice.Element("customname").Value;
答案 1 :(得分:1)
你需要抽象(制作类)你的xml,它会帮助你CRUD并搜索它。
示例:(使用这些扩展程序:http://searisen.com/xmllib/extensions.wiki)
public class Device
{
const bool ELEMENT = false;
const bool ATTRIBUTE = true;
XElement self;
public Device(XElement self) { this.self = self; }
public string CustomName
{
get { return self.Get("customname", string.Empty); }
set { self.Set("customname", value, ELEMENT); }
}
public string Name { get { return self.Get("name", string.Empty); } }
public string Ip { get { return self.Get("ip", "0.0.0.0"); } }
public int Port { get { return self.Get("port", 0); } }
public Source[] Sources
{
get { return _Sources ?? (_Sources = self.GetEnumerable("sources/source", xsource => new Source(xsource)).ToArray()); }
}
Source[] _Sources;
public class Source
{
XElement self;
public Source(XElement self) { this.self = self; }
public string Code { get { return self.Get("code", string.Empty); } }
public string Name { get { return self.Get("name", string.Empty); } }
public bool Hidden { get { return self.Get("hidden", false); } }
}
}
使用它的一个例子:
XElement xdevices = XElement.Load(file.FullName);
Device[] devices = xdevices.GetEnumerable("device", xdevice => new Device(xdevice)).ToArray();
var myDevice = devices
.Where(d => d.Name == App.CurrentDeviceName
&& d.Ip == App.CurrentIp);
foreach (Device device in myDevice)
{
string name = device.Name;
foreach (Device.Source source in device.Sources)
{
string sourceName = source.Name;
}
device.CustomName = "new name";
}
xdevices.Save(file.FullName);
这是思维方式的改变,所以不要担心如何引用值,而是创建类来读取/写入xml,而只是将数据传递给类,即然后读/写xml。
编辑: ----添加到XElementConversions类----
为了与文件保持一致,并且正常工作我制作了详细的版本。您可以修改它们以生成其他类型,例如bool,DateTime等。
public static int GetInt(this XElement source, string name, int defaultValue)
{
source = NameCheck(source, name, out name);
return GetInt(source, source.GetDefaultNamespace() + name, defaultValue);
}
public static int GetInt(this XElement source, XName name, int defaultValue)
{
int result;
if (Int32.TryParse(GetString(source, name, null), out result))
return result;
return defaultValue;
}
答案 2 :(得分:0)
您不应使用XElement.Value
,而是迭代设备XElement
中的XElement
个元素并更改其XText
个节点。或者,您可以使用XAttribute
,因此您不需要制作如此多的嵌套元素。
<Devices>
<Device Name="blah" IP="192.168.1.100" Port="1000">
<Sources>
<Source Code="00" Name="blah2" Hidden="false"/>
</Sources>
</Device>
</Devices>
XElement.Value
是XText
的后代中所有XElement
个节点的串联字符串。如果你set
,则覆盖所有子元素。阅读XElement.Value
答案 3 :(得分:0)
请勿使用XElement.Value Property。使用XElement.ReplaceWith Method。价值的吸气者输出
包含此元素的所有文本内容的String。如果有多个文本节点,它们将被连接。
这意味着子元素的标签将被剥离。
尝试使用此行代替使用值:
device.Element(field).ReplaceWith(updatedDevice.Element(field));