【问题标题】:R: Insert node into xml tree at specific locationR:将节点插入到特定位置的xml树中
【发布时间】: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,所以我没有深入尝试使用它。

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

【问题讨论】:

    标签: xml r search insert tree


    【解决方案1】:

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2012-05-21
      • 1970-01-01
      • 1970-01-01
      • 2021-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-01
      • 1970-01-01
      相关资源
      最近更新 更多