Node Modification

Jim Hester

2021-11-29

Modifying Existing XML

Modifying existing XML can be done in xml2 by using the replacement functions of the accessors. They all have methods for both individual xml_node objects as well as xml_nodeset objects. If a vector of values is provided it is applied piecewise over the nodeset, otherwise the value is recycled.

Text Modification

Text modification only happens on text nodes. If a given node has more than one text node only the first will be affected. If you want to modify additional text nodes you need to select them explicitly with /text().

x <- read_xml("<p>This is some <b>text</b>. This is more.</p>")
xml_text(x)
#> [1] "This is some text. This is more."

xml_text(x) <- "This is some other text."
xml_text(x)
#> [1] "This is some other text.text. This is more."

# You can avoid this by explicitly selecting the text node.
x <- read_xml("<p>This is some text. This is <b>bold!</b></p>")
text_only <- xml_find_all(x, "//text()")

xml_text(text_only) <- c("This is some other text. ", "Still bold!")
xml_text(x)
#> [1] "This is some other text. Still bold!"
xml_structure(x)
#> <p>
#>   {text}
#>   <b>
#>     {text}

Attribute and Namespace Definition Modification

Attributes and namespace definitions are modified one at a time with xml_attr() or all at once with xml_attrs(). In both cases using NULL as the value will remove the attribute completely.

x <- read_xml("<a href='invalid!'>xml2</a>")
xml_attr(x, "href")
#> [1] "invalid!"

xml_attr(x, "href") <- "https://github.com/r-lib/xml2"
xml_attr(x, "href")
#> [1] "https://github.com/r-lib/xml2"

xml_attrs(x) <- c(id = "xml2", href = "https://github.com/r-lib/xml2")
xml_attrs(x)
#>                            href                              id 
#> "https://github.com/r-lib/xml2"                          "xml2"
x
#> {xml_document}
#> <a href="https://github.com/r-lib/xml2" id="xml2">

xml_attrs(x) <- NULL
x
#> {xml_document}
#> <a>

# Namespaces are added with as a xmlns or xmlns:prefix attribute
xml_attr(x, "xmlns") <- "http://foo"
x
#> {xml_document}
#> <a xmlns="http://foo">

xml_attr(x, "xmlns:bar") <- "http://bar"
x
#> {xml_document}
#> <a xmlns="http://foo" xmlns:bar="http://bar">

Name Modification

Node names are modified with xml_name().

x <- read_xml("<a><b/></a>")
x
#> {xml_document}
#> <a>
#> [1] <b/>
xml_name(x)
#> [1] "a"
xml_name(x) <- "c"
x
#> {xml_document}
#> <c>
#> [1] <b/>

Node modification

All of these functions have a .copy argument. If this is set to FALSE they will remove the new node from its location before inserting it into the new location. Otherwise they make a copy of the node before insertion.

Replacing existing nodes

x <- read_xml("<parent><child>1</child><child>2<child>3</child></child></parent>")
children <- xml_children(x)
t1 <- children[[1]]
t2 <- children[[2]]
t3 <- xml_children(children[[2]])[[1]]

xml_replace(t1, t3)
#> {xml_node}
#> <child>
x
#> {xml_document}
#> <parent>
#> [1] <child>3</child>
#> [2] <child>2<child>3</child></child>

Add a sibling

x <- read_xml("<parent><child>1</child><child>2<child>3</child></child></parent>")
children <- xml_children(x)
t1 <- children[[1]]
t2 <- children[[2]]
t3 <- xml_children(children[[2]])[[1]]

xml_add_sibling(t1, t3)
x
#> {xml_document}