我正在用C#编写一个程序,它将通过一堆config.xml文件并更新某些元素,或者如果它们不存在则添加它们。如果元素存在,则我将部分更新为更新元素:
XDocument xdoc = XDocument.Parse(ReadFile(_file));
XElement element = xdoc.Elements("project").Elements("logRotator")
.Elements("daysToKeep").Single();
element.Value = _DoRevert;
但是当我想添加一个不存在的元素时,我遇到了问题。大部分时间树的一部分就位,当我使用我的代码时,它会添加另一个相同的树,这会导致读取xml的程序爆炸。
这是我试图这样做的方式
xdoc.Element("project").Add(new XElement("logRotator", new XElement("daysToKeep", _day)));
导致这样的结构(numToKeep标签已经存在):
<project>
<logRotator>
<daysToKeep>10</daysToKeep>
</logRotator>
<logRotator>
<numToKeep>13</numToKeep>
</logRotator>
</project>
但这就是我想要的
<project>
<logRotator>
<daysToKeep>10</daysToKeep>
<numToKeep>13</numToKeep>
</logRotator>
</project>
答案 0 :(得分:2)
如果存在,则查找给定项目的logRotator元素,如果不存在,则创建该元素。
// project is XElement
XElement logRotator = project.Element("logRotator");
if (logRotator == null)
{
logRotator = new XElement("logRotator");
project.Add(logRotator);
}
logRotator.Add(new XElement("daysToKeep", someValue));
对于可重用性(如果您有其他可能存在或不存在的元素),您可以将其提取到方法中。
static void AddToElement(XElement outerParent, string innerParent, string name, object value)
{
XElement inner = outerParent.Element(innerParent);
if (inner == null)
{
inner = new XElement(innerParent);
outerParent.Add(inner);
}
inner.Add(new XElement(name, value));
}
简单测试
string xml = @"<project>
<logRotator>
<numToKeep>13</numToKeep>
</logRotator>
</project>";
XDocument document = XDocument.Parse(xml);
XElement project = document.Element("project");
AddToElement(project, "logRotator", "daysToKeep", 10);
Console.WriteLine(document.ToString());
答案 1 :(得分:1)
如果numToKeep
已存在,请尝试以下操作:
xdoc.Element("project")
.Element("logRotator")
.Add(new XElement("daysToKeep", _day));
否则,要在logRotator
不存在时添加整行,请使用:
xdoc.Element("project").Add(
new XElement("logRotator",
new XElement("daysToKeep", _day),
new XElement("numToKeep", _num)
));
答案 2 :(得分:0)
随着每个人的kickstart,我最终做到这一点,它的工作原理。它远非优雅,但它完成了工作
/// <summary>
/// adds an element to an xml tree and builds the tree up if it is needed
/// </summary>
/// <param name="outerParent">root node</param>
/// <param name="innerPath">root/childOne/innerParent/name</param>
/// <param name="name">element to add</param>
/// <param name="value">elements value</param>
static XElement BuildTree(XElement outerParent, string innerParentPath, string name, object value)
{
List<string> s = innerParentPath.Split('/').ToList();
string str = "";
XElement prevInner = null;
if (s.Count != 2)//use 2 since we know the root will always be there
{
var t = new List<string>(s);
t.RemoveRange(s.Count - 1, 1);//remove last element
string[] sa = t.ToArray();
str = string.Join("/", sa);
prevInner = BuildTree(outerParent, str, name, value);//call recursively till we get to root;
}
else
{
prevInner = outerParent;
}
XElement inner = prevInner.Element(s[s.Count - 1]);
if (inner == null)
{
if (s[s.Count - 1] == name)//add actual element if we're at top lvl.
{
prevInner.Add(new XElement(name, value));
}
else
{
inner = new XElement(s[s.Count - 1]);
prevInner.Add(inner);
}
}
return inner;
}