简体   繁体   English

使用 linq to xml 在 xml 文档中创建一个节点,如果它不存在

[英]create a node in a xml document if it does not exist using linq to xml

I am querying a xml document using the XPathSelectElement method.我正在使用 XPathSelectElement 方法查询 xml 文档。

if the node does not exist I would like to insert a node with that path in the same document.如果节点不存在,我想在同一个文档中插入一个具有该路径的节点。 The parent nodes should also be created if they do not exist.如果父节点不存在,也应该创建它们。 Is there an easy way to do this without looping through the parents checking if they exist?有没有一种简单的方法可以做到这一点,而无需循环检查父母是否存在? (Add a new node using XPath) (使用 XPath 添加新节点)

No, there is not... this is no different than if you were looking for a Directory on a File System, and had to ensure that all of the parent directories were there to. 不,没有......这与您在文件系统上寻找目录没有什么不同,并且必须确保所有父目录都在那里。

Example: 例:

if (Directory.Exists(@":c:\test1\test2\blah blah\blah blah2")) ...

It's true that the Directory.CreateDirectory method will create all parents that need to be there to have the child show up, but there is no equivalent in XML (using .NET classes, including LINQ-to-XML). 确实,Directory.CreateDirectory方法将创建所有需要在那里显示子项的父项,但XML中没有等效项(使用.NET类,包括LINQ-to-XML)。

You'll have to loop through each one manually. 你必须手动遍历每一个。 I suggest you make a helper method called "EnsureNodeExists" that does that for you :) 我建议你做一个名为“EnsureNodeExists”的辅助方法,为你做这个:)

static private XmlNode makeXPath(XmlDocument doc, string xpath)
{
   return makeXPath(doc, doc as XmlNode, xpath);
}

static private XmlNode makeXPath(XmlDocument doc, XmlNode parent, string   xpath)
{
// grab the next node name in the xpath; or return parent if empty
string[] partsOfXPath = xpath.Trim('/').Split('/');
string nextNodeInXPath = partsOfXPath.First();
if (string.IsNullOrEmpty(nextNodeInXPath))
    return parent;

// get or create the node from the name
XmlNode node = parent.SelectSingleNode(nextNodeInXPath);
if (node == null)
    node = parent.AppendChild(doc.CreateElement(nextNodeInXPath));

// rejoin the remainder of the array as an xpath expression and recurse
string rest = String.Join("/", partsOfXPath.Skip(1).ToArray());
return makeXPath(doc, node, rest);
}

static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml("<feed />");

makeXPath(doc, "/feed/entry/data");
XmlElement contentElement =   (XmlElement)makeXPath(doc,"/feed/entry/content");
contentElement.SetAttribute("source", "");

Console.WriteLine(doc.OuterXml);
}

This is a bit late, but for the next poor soul to come here and find no help here's the static method I ended up writing.这有点晚了,但是对于下一个可怜的灵魂来这里却找不到帮助,这是我最终写的静态方法。 It's not flawless, but should handle a variety of use cases.它并非完美无缺,但应该可以处理各种用例。 Essentially I just go from the bottom of the XPath and keep cutting off sections until I find a match, then go back down the path and create what's missing.本质上,我只是从 XPath 的底部开始并不断切断部分,直到找到匹配项,然后返回路径并创建缺少的部分。 It will fail if you use a path like /root/test//someNode if someNode doesn't exist, but for a path ../someNode//foo/bar/zoot, if ../someNode//foo exists it should work fine.如果 someNode 不存在,则使用 /root/test//someNode 之类的路径会失败,但对于路径 ../someNode//foo/bar/zoot,如果 ../someNode//foo 存在,它应该工作正常。

public static XElement GetOrCreateNodeAtXPath(XDocument doc, string key)
{
    return GetOrCreateNodeAtXPath(doc, key, key);
}
private static XElement GetOrCreateNodeAtXPath(XDocument doc, string key, string originalKey)
{
    var node = doc.XPathSelectElement(key);
    if (node != null)
        return node;
    if (!key.Contains('/'))
        throw new Exception($"Could not create node at path {originalKey}, no part of path matches document");
    var slashIndex = key.LastIndexOf('/');
    var newKey = key.Substring(0, slashIndex);
    var newNodeName = key.Substring(slashIndex + 1);
    var parentNode = GetOrCreateNodeAtXPath(doc, newKey, originalKey);
    var childNode = new XElement(newNodeName);
    parentNode.Add(childNode); 
    return childNode;
}

You may wanna swap XDocument with XElement or XNode or something in the signature, I was just dealign with docs so I used docs.您可能想将 XDocument 与 XElement 或 XNode 或签名中的其他内容交换,我只是与文档对齐,所以我使用了文档。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM