在特定位置将节点插入xml树

5

数据

我有一个类似下面这样的结构的xml文件(为了展示所需的灵活性而提供大量示例):

<rootnode sth="something" descr="ex">
  <tag sth="sth1" descr="ex" anoAttr="sth2">
    <tag sth="sth3" descr="ex2" searchA="sth4" anoAttr="sth5">
      <tag sth="sth6" descr="ex3" oAttr="sth7" searchA="sth8" anoAttr="sth9">
        <tag sth="sth10" descr="ex4" oAttr="sth11" searchA="sth12" anoAttr="sth13">
          <someContent/>
        </tag>
        <someContent/>
      </tag>
      <tag sth="sth14" descr="ex5" oAttr="sth15" searchA="sth16" anoAttr="sth17">
        <someContent/>
      </tag>
      <tag sth="sth1" descr="ex6" oAttr="sth15" searchA="sth18" anoAttr="sth17">
        <someContent/>
      </tag>
    </tag>
    <tag sth="sth10" descr="ex2" oAttr="sth19" searchA="sth20" anoAttr="sth9">
      <someContent/>
    </tag>
    <tag sth="sth10" descr="ex7" searchA="sth21" anoAttr="sth13">
      <tag sth="sth21" descr="ex8" oAttr="sth22" searchA="sth23" anoAttr="sth9">
        <tag sth="sth23" descr="ex9" oAttr="sth22" searchA="sth24" anoAttr="sth5">
          <someContent/>
        </tag>
        <someContent/>
      </tag>
    </tag>
  </tag>
  <otherNode>
    <someNode/>
  </otherNode>
</rootnode>

具体而言,任何tag节点的大小都是未知的,所有tag节点的属性数量不相等且属性值不唯一。
然而,我所知道的是searchA属性的值是唯一的。此外,只有tag节点可以包含名为searchA的属性,除了顶层节点之外的所有节点都包含该属性。

Before

我首先使用XML包中的xmlTreeParse()函数解析此文档并存储根节点。然后,我使用newXMLNode()创建一个新节点。

xmlfile = xmlTreeParse(filename, useInternalNodes = TRUE)
xmltop = xmlRoot(xmlfile)
newNode = newXMLNode(name = "newlyCreatedNode")

目标

我的目标是将新创建的newNode作为具有特定值(例如"sth23")的节点的子节点插入,该节点具有searchA属性。
因此,在这种情况下,我希望结果看起来像这样(请注意底部附近的<newlyCreatedNode/>):

<rootnode sth="something" descr="ex">
  <tag sth="sth1" descr="ex" anoAttr="sth2">
    <tag sth="sth3" descr="ex2" searchA="sth4" anoAttr="sth5">
      <tag sth="sth6" descr="ex3" oAttr="sth7" searchA="sth8" anoAttr="sth9">
        <tag sth="sth10" descr="ex4" oAttr="sth11" searchA="sth12" anoAttr="sth13">
          <someContent/>
        </tag>
        <someContent/>
      </tag>
      <tag sth="sth14" descr="ex5" oAttr="sth15" searchA="sth16" anoAttr="sth17">
        <someContent/>
      </tag>
      <tag sth="sth1" descr="ex6" oAttr="sth15" searchA="sth18" anoAttr="sth17">
        <someContent/>
      </tag>
    </tag>
    <tag sth="sth10" descr="ex2" oAttr="sth19" searchA="sth20" anoAttr="sth9">
      <someContent/>
    </tag>
    <tag sth="sth10" descr="ex7" searchA="sth21" anoAttr="sth13">
      <tag sth="sth21" descr="ex8" oAttr="sth22" searchA="sth23" anoAttr="sth9">
        <tag sth="sth23" descr="ex9" oAttr="sth22" searchA="sth24" anoAttr="sth5">
          <someContent/>
        </tag>
        <someContent/>
        <newlyCreatedNode/>
      </tag>
    </tag>
  </tag>
  <otherNode>
    <someNode/>
  </otherNode>
</rootnode>

基本上,这种情况下addChildren(xmltop[[1]][[3]][[1]], kids = list(newNode))可以给我想要的结果。当然我不想指定[[1]][[3]][[1]]

我尝试过的方法

我可以使用xmlElementsByTagName()获取所有相关节点的列表,并使用xmlAttrs()获取所有属性。我甚至还可以获得一个逻辑索引向量,它可以给我正确的位置。

listOfNodes = xmlElementsByTagName(el = xmltop, "tag", recursive = T)
attributeList = lapply(listOfNodes, FUN = function(x) xmlAttrs(x))
indexVector = sapply(attributeList, FUN = function(x) x["searchA"] == "sth23")
indexVector[is.na(indexVector)] = FALSE
listOfNodes[indexVector]

我不知道如何使用这些信息将我的节点插入到正确的位置。
listOfNodes[indexVector] 给出了正确的节点,但它现在是一个列表,而不是我可以在上面使用 addChildren() 的节点。
即使我设法将 `indexVector` 和所有节点的 `xmlSize()` 映射到可以直接在 `xmltop` 上使用的正确索引,我仍然会遇到一个变量数量的双括号问题(`xmltop[[1]][[3]]` vs `xmltop[[1]][[2]][[1]]`)。
我还尝试了 XML 包的其他几个函数,包括 xmlApplygetNodeLocationgetNodeSet,但它们似乎没有帮助。

我尚未真正尝试过的方法

我真的不理解 xmlTreeParse()xmlInternalTreeParse()xmlTreeParse(useInternalNodes=T) 的区别,也无法理解 XPath,因此我在尝试使用它时没有取得很大进展。
任何有用的提示都将不胜感激。
1个回答

0
我困惑的原因是对于函数?xmlElementsByTagName的帮助页面说明如下:

“添加 recursive 参数使此函数的行为类似于其他语言 API(如 Java、C#)中的 getElementsByTagName。但是,应该注意,这些语言中会返回一组节点对象。这些节点具有对其父级和子级的引用。因此,可以从每个节点遍历树,查找其关系等。在此软件包的当前版本(以及可预见的未来),节点集合是原始树中节点的“副本”。而这些没有查找它们的兄弟或父母的工具。”

这使我认为该函数返回的是副本列表,而不是节点本身的引用。
如果使用xmlTreeParse()函数的标志useInternalNodes设置为FALSE解析xml,则可能是这种情况,但如果解析时将其设置为TRUE,则xmlElementsByTagName()返回的列表似乎包含实际的引用。
可以使用例如addChildren()轻松操纵它们。

简而言之,解决我的问题的非常简单的方法是:
addChildren(listOfNodes[indexVector], kids = list(newNode))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接