R: Insert node into xml tree at specific location
<h2>Data</h2>

<p>I have an xml file with a structure like this (large example to show the needed flexibility):</p>

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

<p>Specifically, the size of any of the <code>tag</code> nodes is unknown, the number of attributes is not equal for all <code>tag</code> nodes and the values of the attributes are not unique.<br>
What I do know, however, is that the value of the <code>searchA</code> attribute is unique. Also, only <code>tag</code> nodes can contain an attribute called <code>searchA</code> and all of them except the top level one do.</p>

<h2>Before</h2>

<p>I first parse this document using the <code>XML</code> package with the function <code>xmlTreeParse()</code> and store the root node. I then create a new node using <code>newXMLNode()</code>.</p>

<pre><code>xmlfile = xmlTreeParse(filename, useInternalNodes = TRUE)
xmltop = xmlRoot(xmlfile)
newNode = newXMLNode(name = "newlyCreatedNode")
</code></pre>

<h2>Goal</h2>

<p>My goal is to insert my newly created <code>newNode</code> as a child of the node that has a certain value (for example <code>"sth23"</code>) as the <code>searchA</code> attribute.<br>
So in this case I want the result to look like this (notice the <code>&lt;newlyCreatedNode/&gt;</code> near the bottom):</p>

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

<p>Basically, in this case <code>addChildren(xmltop[[1]][[3]][[1]], kids = list(newNode))</code> gets me the result that I want. Of course I do not want to specify <code>[[1]][[3]][[1]]</code>.</p>

<h2>What I tried</h2>

<p>I can get a list of all relevant nodes with <code>xmlElementsByTagName()</code> and get all attributes with <code>xmlAttrs()</code>. I can even get a logical index vector which gives me the correct location.</p>

<pre><code>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]
</code></pre>

<p>What I do not know is how to use this information to insert my node into the tree at the correct location.<br>
<code>listOfNodes[indexVector]</code> gives me the correct node, but it is now a list and not a node I can use <code>addChildren()</code> on.<br>
Even if I somehow managed to map the <code>indexVector</code> and the <code>xmlSize()</code> of all nodes to the correct indices that I could use on <code>xmltop</code> directly, I would still have the problem of a variable number of double brackets (<code>xmltop[[1]][[3]]</code> vs <code>xmltop[[1]][[2]][[1]]</code>).</p>

<p>I have also tried several other functions of the <code>XML</code> package, including <code>xmlApply</code>, <code>getNodeLocation</code> and <code>getNodeSet</code>, but they did not seem to help.</p>

<h2>What I have not really tried</h2>

<p>I do not really understand the difference of <code>xmlTreeParse()</code>, <code>xmlInternalTreeParse()</code> and <code>xmlTreeParse(useInternalNodes = T)</code> and I cannot wrap my head around XPath, so I did not get very far trying to use it.</p>

<p>Any helpful pointers would be much appreciated.</p>