File: extract_xml.cpp

package info (click to toggle)
ltt-control 2.14.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 22,400 kB
  • sloc: cpp: 192,720; sh: 29,271; ansic: 10,960; python: 7,419; makefile: 3,534; java: 109; xml: 46
file content (288 lines) | stat: -rw-r--r-- 6,016 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/*
 * SPDX-FileCopyrightText: 2014 EfficiOS Inc.
 *
 * SPDX-License-Identifier: GPL-2.0-only
 *
 */

/*
 * Usage: extract_xml [-v|-e] xml_path xpath_expression
 * Evaluate XPath expression and prints result node set.
 * args[1] path to the xml file
 * args[2] xpath expression to extract
 * If -e look if node exist return "true" else nothing
 * If -v is set the name of the node will appear with his value delimited by
 * a semicolon(;)
 * Ex:
 * Command:extract_xml ../file.xml /test/node/text()
 * Output:
 *     a
 *     b
 *     c
 * With -v
 *     node;a;
 *     node;b;
 *     node;c;
 */
#include "common.hpp"

#include <common/defaults.hpp>

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

namespace ll = lttng::libxml;

#if defined(LIBXML_XPATH_ENABLED)

static int opt_verbose;
static int node_exist;
static bool result = false;

/*
 * print_xpath_nodes:
 * nodes:  the nodes set.
 * output: the output file handle.
 *
 * Print the node content to the file
 */
static int print_xpath_nodes(xmlDocPtr doc, xmlNodeSetPtr nodes, FILE *output)
{
	int ret = 0;
	int size;
	int i;

	xmlNodePtr cur;
	xmlChar *node_child_value_string = nullptr;

	LTTNG_ASSERT(output);
	size = (nodes) ? nodes->nodeNr : 0;

	for (i = 0; i < size; ++i) {
		LTTNG_ASSERT(nodes->nodeTab[i]);

		if (nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) {
			fprintf(stderr,
				"ERR:%s\n",
				"This executable does not support xml namespacing\n");
			ret = -1;
			goto end;
		} else if (nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
			cur = nodes->nodeTab[i];

			if (xmlChildElementCount(cur) == 0) {
				if (xmlNodeIsText(cur->children)) {
					node_child_value_string =
						xmlNodeListGetString(doc, cur->children, 1);
					if (node_exist) {
						result = true;
					} else if (opt_verbose) {
						fprintf(output,
							"%s;%s;\n",
							cur->name,
							node_child_value_string);
					} else {
						fprintf(output, "%s\n", node_child_value_string);
					}
					xmlFree(node_child_value_string);
				} else {
					/* We don't want to print non-final element */
					if (node_exist) {
						result = true;
					} else {
						fprintf(stderr,
							"ERR:%s\n",
							"Xpath expression return non-final xml element");
						ret = -1;
						goto end;
					}
				}
			} else {
				if (node_exist) {
					result = true;
				} else {
					/* We don't want to print non-final element */
					fprintf(stderr,
						"ERR:%s\n",
						"Xpath expression return non-final xml element");
					ret = -1;
					goto end;
				}
			}

		} else {
			cur = nodes->nodeTab[i];
			if (node_exist) {
				result = true;
			} else if (opt_verbose) {
				fprintf(output, "%s;%s;\n", cur->parent->name, cur->content);
			} else {
				fprintf(output, "%s\n", cur->content);
			}
		}
	}
	/* Command Success */
	ret = 0;

end:
	return ret;
}

static int register_lttng_namespace(xmlXPathContextPtr xpathCtx)
{
	int ret;
	xmlChar *prefix;
	xmlChar *ns = nullptr;

	prefix = xmlCharStrdup("lttng");
	if (!prefix) {
		ret = -1;
		goto end;
	}

	ns = xmlCharStrdup(DEFAULT_LTTNG_MI_NAMESPACE);
	if (!ns) {
		ret = -1;
		goto end;
	}

	ret = xmlXPathRegisterNs(xpathCtx, prefix, ns);
end:
	xmlFree(prefix);
	xmlFree(ns);
	return ret;
}

/*
 * Extract element corresponding to xpath
 * xml_path     The path to the xml file
 * xpath:       The xpath to evaluate.
 *
 * Evaluate an xpath expression onto an xml file.
 * and print the result one by line.
 *
 * Returns 0 on success and a negative value otherwise.
 */
static int extract_xpath(const char *xml_path, const xmlChar *xpath)
{
	int ret;
	xmlDocPtr doc = nullptr;
	xmlXPathContextPtr xpathCtx = nullptr;
	xmlXPathObjectPtr xpathObj = nullptr;

	LTTNG_ASSERT(xml_path);
	LTTNG_ASSERT(xpath);

	const ll::parser_ctx_uptr parserCtx{ xmlNewParserCtxt() };

	if (!parserCtx) {
		fprintf(stderr, "ERR: could not allocate an XML parser context\n");
		return -1;
	}

	/* Parse the xml file */
	doc = xmlCtxtReadFile(parserCtx.get(), xml_path, nullptr, XML_PARSE_NOBLANKS);
	if (!doc) {
		fprintf(stderr, "ERR parsing: xml file invalid \"%s\"\n", xml_path);
		return -1;
	}

	/* Initialize a xpath context */
	xpathCtx = xmlXPathNewContext(doc);
	if (!xpathCtx) {
		fprintf(stderr, "ERR: XPath context invalid\n");
		xmlFreeDoc(doc);
		return -1;
	}

	/* Register the LTTng MI namespace */
	ret = register_lttng_namespace(xpathCtx);
	if (ret) {
		fprintf(stderr, "ERR: Could not register lttng namespace\n");
		xmlXPathFreeContext(xpathCtx);
		xmlFreeDoc(doc);
		return -1;
	}

	/* Evaluate xpath expression */
	xpathObj = xmlXPathEvalExpression(xpath, xpathCtx);
	if (!xpathObj) {
		fprintf(stderr, "ERR: invalid xpath expression \"%s\"\n", xpath);
		xmlXPathFreeContext(xpathCtx);
		xmlFreeDoc(doc);
		return -1;
	}

	/* Print results */
	if (print_xpath_nodes(doc, xpathObj->nodesetval, stdout)) {
		xmlXPathFreeObject(xpathObj);
		xmlXPathFreeContext(xpathCtx);
		xmlFreeDoc(doc);
		return -1;
	}
	if (node_exist && result) {
		fprintf(stdout, "true\n");
	}

	/* Cleanup */
	xmlXPathFreeObject(xpathObj);
	xmlXPathFreeContext(xpathCtx);
	xmlFreeDoc(doc);

	return 0;
}

int main(int argc, char **argv)
{
	int opt;

	/* Parse command line and process file */
	while ((opt = getopt(argc, argv, "ve")) != -1) {
		switch (opt) {
		case 'v':
			opt_verbose = 1;
			break;
		case 'e':
			node_exist = 1;
			break;
		default:
			abort();
		}
	}

	if (!(optind + 1 < argc)) {
		fprintf(stderr, "ERR:%s\n", "Arguments missing");
		return -1;
	}

	/* Init libxml */
	xmlInitParser();
	if (access(argv[optind], F_OK)) {
		fprintf(stderr, "ERR:%s\n", "Xml path not valid");
		return -1;
	}
	/* Do the main job */
	if (extract_xpath(argv[optind], (xmlChar *) argv[optind + 1])) {
		return -1;
	}

	/* Shutdown libxml */
	xmlCleanupParser();

	return 0;
}

#else
int main(void)
{
	fprintf(stderr, "XPath support not compiled in\n");
	return -1;
}
#endif