是否有可用的方法(即没有我创建自己的递归方法),对于给定的xpath(或其他识别分层位置的方法)来创建/更新XML节点,如果有的话,将创建节点不存在?如果父节点也不存在,则需要创建父节点。我有一个包含所有可能节点的XSD。
即。 之前:
<employee>
<name>John Smith</name>
</employee>
想要打这样的话:
CoolXmlUpdateMethod("/employee/address/city", "Los Angeles");
之后:
<employee>
<name>John Smith</name>
<address>
<city>Los Angeles</city>
</address>
</employee>
甚至是给定xpath创建节点的方法,如果它们不存在,它将递归地创建父节点?
就应用程序而言(如果重要),这将采用仅包含已填充节点的现有XML文档,并从另一个系统向其添加数据。新数据可能已经或可能没有在源XML中填充的值。
当然这不是一个不寻常的情况吗?
答案 0 :(得分:2)
Chris Knight的解决方案有一个错误。如果你有:
<a></a>
<b>
<a>
</a>
</b>
and do
UpdateOrCreate ("<b><a>")
it will update first node , not nested one.
这是我的功能:
/// <summary>
/// Creates nessecary parent nodes using the provided Queue, and assigns the value to the last child node.
/// </summary>
/// <param name="ele">XElement to take action on</param>
/// <param name="nodes">Queue of node names</param>
/// <param name="value">Value for last child node</param>
/// <param name="attr1Name">Optional name for an attribute, can be null</param>
/// <param name="attr1Val">Optional value for an attribute, can be null</param>
/// returns created/updated element
public static XElement UpdateOrCreateXmlNode(XElement ele, Queue<string> nodes, string value, string attr1Name = null, string attr1Val = null)
{
int fullQueueCOunt = nodes.Count;
for (int i = 0; i < fullQueueCOunt; i++)
{
string node = nodes.Dequeue();
XElement firstChildMatch = ele.Elements(node).FirstOrDefault();
if (firstChildMatch == null)
{
XElement newChlid = new XElement(node);
ele.Add(newChlid);
ele = newChlid;
}
else
ele = firstChildMatch;
}
if (attr1Name != null && attr1Val != null)
{
if (ele.Attribute(attr1Name) == null)
ele.Add(new XAttribute(attr1Name, attr1Val));
else
ele.Attribute(attr1Name).Value = attr1Val;
}
ele.Value = value;
return ele;
}
答案 1 :(得分:1)
好吧,我们要做的是创建一个代表XML的类(我们使用XSD2Code从XSD生成一个),当它被反序列化/序列化时,它可以为你做这样的事情(XMLSerializer) )。
答案 2 :(得分:1)
之前我做过类似的事。我正在使用LINQ to XML。我为XElement创建了一个扩展方法,它接受节点名称的队列,以及列表中最后一个节点的值。这是我做的扩展方法:
/// <summary>
/// Creates nessecary parent nodes using the provided Queue, and assigns the value to the last child node.
/// </summary>
/// <param name="ele">XElement to take action on</param>
/// <param name="nodes">Queue of node names</param>
/// <param name="value">Value for last child node</param>
public static void UpdateOrCreate(this XElement ele, Queue<string> nodes, string value)
{
string previousNodeName = "";
int fullQueueCOunt = nodes.Count;
for (int i = 0; i < fullQueueCOunt; i++)
{
string node = nodes.Dequeue();
if (ele.Descendants(node).FirstOrDefault() == null)
{
if (!string.IsNullOrEmpty(previousNodeName))
{
ele.Element(previousNodeName).Add(new XElement(node));
}
else
{
// use main parent node if this is the first iteration
ele.Add(new XElement(node));
}
}
previousNodeName = node;
}
// assign the value of the last child element
ele.Descendants(previousNodeName).First().Value = value;
}
这是一个示例实现:
XElement element = XElement.Parse(
"<employee>" +
"<name>John Smith</name>" +
"</employee>");
Queue<string> nodeQueue = new Queue<string>();
nodeQueue.Enqueue("address");
nodeQueue.Enqueue("city");
element.UpdateOrCreate(nodeQueue, "myValue");
这将采用输入XML:
<employee>
<name>John Smith</name>
</employee>
并将其更改为:
<employee>
<name>John Smith</name>
<address>
<city>myValue</city>
</address>
</employee>
如果“地址”和/或“城市”节点已经存在,这也可以使用。
答案 3 :(得分:0)
我自己也在努力解决这个问题,所以我想添加一个使用C#的.Net 2.0的答案。
private static void addOrUpdateNode(XmlDocument xmlDoc, string xpath, string value)
{
XmlNode node = xmlDoc.SelectSingleNode(xpath);
if (node == null)
{
//node does not exist, so create it
string newNodeString = String.Format(
"<city>{0}</city>", value); //as per OP's example
StringReader sr = new StringReader(newNodeString);
XmlTextReader reader = new XmlTextReader(sr);
XmlNode newNode = xmlDoc.ReadNode(reader);
//adding to root of document, you may want to
//navigate to a different part of the doc
xmlDoc.AppendChild(newNode);
}
else
{
node.Value = value;
}
}
原谅我让它非常粗糙和未经测试,任何想要清理它的人都可以自由编辑。