|
12 | 12 |
|
13 | 13 | #' @param xpath A string containing a xpath (1.0) expression. |
14 | 14 | #' @inheritParams xml_name |
15 | | -#' @return `xml_find_all` always returns a nodeset: if there are no matches |
16 | | -#' the nodeset will be empty. The result will always be unique; repeated |
17 | | -#' nodes are automatically de-duplicated. |
| 15 | +#' @param ... Further arguments passed to or from other methods. |
| 16 | +#' @return `xml_find_all` returns a nodeset if applied to a node, and a nodeset |
| 17 | +#' or a list of nodesets if applied to a nodeset. If there are no matches, |
| 18 | +#' the nodeset(s) will be empty. Within each nodeset, the result will always |
| 19 | +#' be unique; repeated nodes are automatically de-duplicated. |
18 | 20 | #' |
19 | 21 | #' `xml_find_first` returns a node if applied to a node, and a nodeset |
20 | 22 | #' if applied to a nodeset. The output is *always* the same size as |
|
46 | 48 | #' </body>") |
47 | 49 | #' para <- xml_find_all(x, ".//p") |
48 | 50 | #' |
49 | | -#' # If you apply xml_find_all to a nodeset, it finds all matches, |
50 | | -#' # de-duplicates them, and returns as a single list. This means you |
| 51 | +#' # By default, if you apply xml_find_all to a nodeset, it finds all matches, |
| 52 | +#' # de-duplicates them, and returns as a single nodeset. This means you |
51 | 53 | #' # never know how many results you'll get |
52 | 54 | #' xml_find_all(para, ".//b") |
53 | 55 | #' |
| 56 | +#' # If you set flatten to FALSE, though, xml_find_all will return a list of |
| 57 | +#' # nodesets, where each nodeset contains the matches for the corresponding |
| 58 | +#' # node in the original nodeset. |
| 59 | +#' xml_find_all(para, ".//b", flatten = FALSE) |
| 60 | +#' |
54 | 61 | #' # xml_find_first only returns the first match per input node. If there are 0 |
55 | 62 | #' # matches it will return a missing node |
56 | 63 | #' xml_find_first(para, ".//b") |
|
67 | 74 | #' ') |
68 | 75 | #' xml_find_all(x, ".//f:doc") |
69 | 76 | #' xml_find_all(x, ".//f:doc", xml_ns(x)) |
70 | | -xml_find_all <- function(x, xpath, ns = xml_ns(x)) { |
| 77 | +xml_find_all <- function(x, xpath, ns = xml_ns(x), ...) { |
71 | 78 | UseMethod("xml_find_all") |
72 | 79 | } |
73 | 80 |
|
74 | 81 | #' @export |
75 | | -xml_find_all.xml_missing <- function(x, xpath, ns = xml_ns(x)) { |
| 82 | +xml_find_all.xml_missing <- function(x, xpath, ns = xml_ns(x), ...) { |
76 | 83 | xml_nodeset() |
77 | 84 | } |
78 | 85 |
|
79 | 86 | #' @export |
80 | | -xml_find_all.xml_node <- function(x, xpath, ns = xml_ns(x)) { |
| 87 | +xml_find_all.xml_node <- function(x, xpath, ns = xml_ns(x), ...) { |
81 | 88 | nodes <- .Call(xpath_search, x$node, x$doc, xpath, ns, Inf) |
82 | 89 | xml_nodeset(nodes) |
83 | 90 | } |
84 | 91 |
|
| 92 | +#' @param flatten A logical indicating whether to return a single, flattened |
| 93 | +#' nodeset or a list of nodesets. |
85 | 94 | #' @export |
86 | | -xml_find_all.xml_nodeset <- function(x, xpath, ns = xml_ns(x)) { |
| 95 | +#' @rdname xml_find_all |
| 96 | +xml_find_all.xml_nodeset <- function(x, xpath, ns = xml_ns(x), flatten = TRUE, ...) { |
87 | 97 | if (length(x) == 0) |
88 | 98 | return(xml_nodeset()) |
89 | 99 |
|
90 | | - nodes <- unlist(recursive = FALSE, |
91 | | - lapply(x, function(x) |
92 | | - .Call(xpath_search, x$node, x$doc, xpath, ns, Inf))) |
| 100 | + res <- lapply(x, function(x) .Call(xpath_search, x$node, x$doc, xpath, ns, Inf)) |
93 | 101 |
|
94 | | - xml_nodeset(nodes) |
| 102 | + if (isTRUE(flatten)) { |
| 103 | + return(xml_nodeset(unlist(recursive = FALSE, res))) |
| 104 | + } |
| 105 | + |
| 106 | + res[] <- lapply(res, xml_nodeset) |
| 107 | + res |
95 | 108 | } |
96 | 109 |
|
97 | 110 | #' @export |
|
0 commit comments