Clean-up: modernize pretty_xml.cpp
[lttng-tools.git] / tests / utils / xml-utils / extract_xml.cpp
CommitLineData
68270f0f 1/*
4b2b86f2 2 * Copyright (C) 2014 EfficiOS Inc.
68270f0f 3 *
9d16b343 4 * SPDX-License-Identifier: GPL-2.0-only
68270f0f 5 *
68270f0f
JRJ
6 */
7
8/*
71f82f2b 9 * Usage: extract_xml [-v|-e] xml_path xpath_expression
68270f0f
JRJ
10 * Evaluate XPath expression and prints result node set.
11 * args[1] path to the xml file
12 * args[2] xpath expression to extract
71f82f2b 13 * If -e look if node exist return "true" else nothing
68270f0f
JRJ
14 * If -v is set the name of the node will appear with his value delimited by
15 * a semicolon(;)
16 * Ex:
17 * Command:extract_xml ../file.xml /test/node/text()
18 * Output:
19 * a
20 * b
21 * c
22 * With -v
23 * node;a;
24 * node;b;
25 * node;c;
26 */
051356a8
SM
27#include "common.hpp"
28
28ab034a
JG
29#include <common/defaults.hpp>
30
31#include <libxml/parser.h>
32#include <libxml/tree.h>
33#include <libxml/xpath.h>
34#include <libxml/xpathInternals.h>
83d6d6c4 35#include <stdbool.h>
68270f0f 36#include <stdio.h>
83d6d6c4 37#include <stdlib.h>
68270f0f 38#include <string.h>
68270f0f
JRJ
39#include <unistd.h>
40
f59edc7c
JG
41namespace ll = lttng::libxml;
42
68270f0f
JRJ
43#if defined(LIBXML_XPATH_ENABLED)
44
83d6d6c4
JR
45static int opt_verbose;
46static int node_exist;
47static bool result = false;
71f82f2b 48
68270f0f
JRJ
49/**
50 * print_xpath_nodes:
51 * nodes: the nodes set.
52 * output: the output file handle.
53 *
54 * Print the node content to the file
55 */
56static int print_xpath_nodes(xmlDocPtr doc, xmlNodeSetPtr nodes, FILE *output)
57{
71f82f2b 58 int ret = 0;
68270f0f
JRJ
59 int size;
60 int i;
61
62 xmlNodePtr cur;
cd9adb8b 63 xmlChar *node_child_value_string = nullptr;
68270f0f 64
a0377dfe 65 LTTNG_ASSERT(output);
68270f0f
JRJ
66 size = (nodes) ? nodes->nodeNr : 0;
67
68 for (i = 0; i < size; ++i) {
a0377dfe 69 LTTNG_ASSERT(nodes->nodeTab[i]);
68270f0f
JRJ
70
71 if (nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) {
28ab034a
JG
72 fprintf(stderr,
73 "ERR:%s\n",
74 "This executable does not support xml namespacing\n");
68270f0f
JRJ
75 ret = -1;
76 goto end;
77 } else if (nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
78 cur = nodes->nodeTab[i];
79
80 if (xmlChildElementCount(cur) == 0) {
81 if (xmlNodeIsText(cur->children)) {
28ab034a
JG
82 node_child_value_string =
83 xmlNodeListGetString(doc, cur->children, 1);
71f82f2b 84 if (node_exist) {
83d6d6c4 85 result = true;
71f82f2b 86 } else if (opt_verbose) {
28ab034a
JG
87 fprintf(output,
88 "%s;%s;\n",
89 cur->name,
90 node_child_value_string);
68270f0f 91 } else {
28ab034a 92 fprintf(output, "%s\n", node_child_value_string);
68270f0f
JRJ
93 }
94 xmlFree(node_child_value_string);
71f82f2b
JR
95 } else {
96 /* We don't want to print non-final element */
97 if (node_exist) {
83d6d6c4 98 result = true;
71f82f2b 99 } else {
28ab034a
JG
100 fprintf(stderr,
101 "ERR:%s\n",
102 "Xpath expression return non-final xml element");
71f82f2b
JR
103 ret = -1;
104 goto end;
105 }
106 }
107 } else {
108 if (node_exist) {
83d6d6c4 109 result = true;
68270f0f
JRJ
110 } else {
111 /* We don't want to print non-final element */
28ab034a
JG
112 fprintf(stderr,
113 "ERR:%s\n",
114 "Xpath expression return non-final xml element");
68270f0f
JRJ
115 ret = -1;
116 goto end;
117 }
68270f0f
JRJ
118 }
119
120 } else {
121 cur = nodes->nodeTab[i];
71f82f2b 122 if (node_exist) {
83d6d6c4 123 result = true;
71f82f2b 124 } else if (opt_verbose) {
68270f0f
JRJ
125 fprintf(output, "%s;%s;\n", cur->parent->name, cur->content);
126 } else {
127 fprintf(output, "%s\n", cur->content);
68270f0f
JRJ
128 }
129 }
130 }
131 /* Command Success */
132 ret = 0;
133
134end:
135 return ret;
136}
137
41af1adf
JG
138static int register_lttng_namespace(xmlXPathContextPtr xpathCtx)
139{
140 int ret;
141 xmlChar *prefix;
cd9adb8b 142 xmlChar *ns = nullptr;
41af1adf
JG
143
144 prefix = xmlCharStrdup("lttng");
145 if (!prefix) {
146 ret = -1;
147 goto end;
148 }
149
150 ns = xmlCharStrdup(DEFAULT_LTTNG_MI_NAMESPACE);
151 if (!ns) {
152 ret = -1;
153 goto end;
154 }
155
156 ret = xmlXPathRegisterNs(xpathCtx, prefix, ns);
41af1adf 157end:
0916f272 158 xmlFree(prefix);
41af1adf
JG
159 xmlFree(ns);
160 return ret;
161}
162
68270f0f
JRJ
163/*
164 * Extract element corresponding to xpath
165 * xml_path The path to the xml file
166 * xpath: The xpath to evaluate.
167 *
168 * Evaluate an xpath expression onto an xml file.
169 * and print the result one by line.
170 *
171 * Returns 0 on success and a negative value otherwise.
172 */
173static int extract_xpath(const char *xml_path, const xmlChar *xpath)
174{
41af1adf 175 int ret;
cd9adb8b
JG
176 xmlDocPtr doc = nullptr;
177 xmlXPathContextPtr xpathCtx = nullptr;
178 xmlXPathObjectPtr xpathObj = nullptr;
68270f0f 179
a0377dfe
FD
180 LTTNG_ASSERT(xml_path);
181 LTTNG_ASSERT(xpath);
68270f0f 182
f59edc7c 183 ll::parser_ctx_uptr parserCtx{ xmlNewParserCtxt() };
051356a8
SM
184
185 if (!parserCtx) {
186 fprintf(stderr, "ERR: could not allocate an XML parser context\n");
187 return -1;
188 }
189
68270f0f 190 /* Parse the xml file */
051356a8 191 doc = xmlCtxtReadFile(parserCtx.get(), xml_path, nullptr, XML_PARSE_NOBLANKS);
68270f0f
JRJ
192 if (!doc) {
193 fprintf(stderr, "ERR parsing: xml file invalid \"%s\"\n", xml_path);
194 return -1;
195 }
196
197 /* Initialize a xpath context */
198 xpathCtx = xmlXPathNewContext(doc);
199 if (!xpathCtx) {
200 fprintf(stderr, "ERR: XPath context invalid\n");
201 xmlFreeDoc(doc);
202 return -1;
203 }
204
41af1adf
JG
205 /* Register the LTTng MI namespace */
206 ret = register_lttng_namespace(xpathCtx);
207 if (ret) {
208 fprintf(stderr, "ERR: Could not register lttng namespace\n");
209 xmlXPathFreeContext(xpathCtx);
210 xmlFreeDoc(doc);
211 return -1;
212 }
213
68270f0f
JRJ
214 /* Evaluate xpath expression */
215 xpathObj = xmlXPathEvalExpression(xpath, xpathCtx);
216 if (!xpathObj) {
217 fprintf(stderr, "ERR: invalid xpath expression \"%s\"\n", xpath);
218 xmlXPathFreeContext(xpathCtx);
219 xmlFreeDoc(doc);
220 return -1;
221 }
222
223 /* Print results */
224 if (print_xpath_nodes(doc, xpathObj->nodesetval, stdout)) {
225 xmlXPathFreeObject(xpathObj);
226 xmlXPathFreeContext(xpathCtx);
227 xmlFreeDoc(doc);
228 return -1;
229 }
83d6d6c4
JR
230 if (node_exist && result) {
231 fprintf(stdout, "true\n");
232 }
68270f0f
JRJ
233
234 /* Cleanup */
235 xmlXPathFreeObject(xpathObj);
236 xmlXPathFreeContext(xpathCtx);
237 xmlFreeDoc(doc);
238
239 return 0;
240}
241
242int main(int argc, char **argv)
243{
244 int opt;
245
246 /* Parse command line and process file */
71f82f2b 247 while ((opt = getopt(argc, argv, "ve")) != -1) {
68270f0f
JRJ
248 switch (opt) {
249 case 'v':
250 opt_verbose = 1;
251 break;
71f82f2b
JR
252 case 'e':
253 node_exist = 1;
254 break;
68270f0f
JRJ
255 default:
256 abort();
257 }
258 }
259
260 if (!(optind + 1 < argc)) {
261 fprintf(stderr, "ERR:%s\n", "Arguments missing");
262 return -1;
263 }
264
265 /* Init libxml */
266 xmlInitParser();
68270f0f
JRJ
267 if (access(argv[optind], F_OK)) {
268 fprintf(stderr, "ERR:%s\n", "Xml path not valid");
269 return -1;
270 }
271 /* Do the main job */
28ab034a 272 if (extract_xpath(argv[optind], (xmlChar *) argv[optind + 1])) {
68270f0f
JRJ
273 return -1;
274 }
275
276 /* Shutdown libxml */
277 xmlCleanupParser();
278
279 return 0;
280}
281
282#else
283int main(void)
284{
285 fprintf(stderr, "XPath support not compiled in\n");
286 return -1;
287}
288#endif
This page took 0.068964 seconds and 4 git commands to generate.