R:将节点插入到特定位置的xml树中

Posted

技术标签:

【中文标题】R:将节点插入到特定位置的xml树中【英文标题】:R: Insert node into xml tree at specific location 【发布时间】:2016-05-14 02:42:21 【问题描述】:

数据

我有一个类似这样结构的 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 的属性,并且除了***节点之外的所有节点都可以。

之前

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

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

目标

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

<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() on。 即使我设法将所有节点的indexVectorxmlSize() 映射到我可以直接在xmltop 上使用的正确索引,我仍然会遇到双括号数量可变的问题(xmltop[[1]][[3]]xmltop[[1]][[2]][[1]])。

我还尝试了XML包的其他几个功能,包括xmlApplygetNodeLocationgetNodeSet,但它们似乎没有帮助。

我没有真正尝试过的东西

我不太了解xmlTreeParse()xmlInternalTreeParse()xmlTreeParse(useInternalNodes = T) 的区别,而且我无法完全理解 XPath,所以我没有深入尝试使用它。

任何有用的指针将不胜感激。

【问题讨论】:

【参考方案1】:

我感到困惑的原因是?xmlElementsByTagName 的帮助页面。上面写着:

recursive 参数的添加使该函数的行为类似于 Java、C\# 等其他语言 API 中的 getElementsByTagName。但是,应该注意理解在那些语言中,人们会返回一组节点对象。这些节点具有对其父母和孩子的引用。因此,人们可以从每个节点导航树,找到它的关系等。在这个包的当前版本中(并且在可预见的未来),节点集是原始树中节点的“副本”。这些节点无法找到它们的兄弟姐妹或父节点。”

这让我觉得该函数返回一个副本列表,而不是对节点本身的引用。 如果在解析 xml 时将 xmlTreeParse() 函数的标志 useInternalNodes 设置为 FALSE,则可能会出现这种情况,但如果在解析时将其设置为 TRUE,则 xmlElementsByTagName() 返回的列表似乎包含实际参考。 这些可以很容易地使用例如addChildren()进行操作。

简而言之,解决我的问题的非常简单的方法是:

addChildren(listOfNodes[indexVector], kids = list(newNode))

【讨论】:

以上是关于R:将节点插入到特定位置的xml树中的主要内容,如果未能解决你的问题,请参考以下文章

在 xml 文件中的特定节点之后插入一个节点

第二季 第四集 part3

第六十三课 二叉树中的结点插入操作

第五十四课 树中节点的插入操作

selenium入门:Xpath定位-绝对定位

如何修复关闭后插入的 XML 节点