xml.c 19.7 KB
Newer Older
1 2 3
/*
 * xml.c: XML based interfaces for the libvir library
 *
4
 * Copyright (C) 2005, 2007-2011 Red Hat, Inc.
5 6 7 8 9 10
 *
 * See COPYING.LIB for the License of this software
 *
 * Daniel Veillard <veillard@redhat.com>
 */

11
#include <config.h>
12

13 14 15 16
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
17
#include <limits.h>
18
#include <math.h>               /* for isnan() */
19 20

#include "virterror_internal.h"
21
#include "xml.h"
22
#include "buf.h"
23
#include "util.h"
24
#include "memory.h"
25

26 27
#define VIR_FROM_THIS VIR_FROM_XML

28 29
#define virGenericReportError(from, code, ...)                          \
        virReportErrorHelper(NULL, from, code, __FILE__,                \
30
                             __FUNCTION__, __LINE__, __VA_ARGS__)
31

32 33 34 35 36 37 38 39 40
#define virXMLError(code, ...)                                          \
        virGenericReportError(VIR_FROM_XML, code, __VA_ARGS__)


/* Internal data to be passed to SAX parser and used by error handler. */
struct virParserData {
    int domcode;
};

41 42 43 44 45 46 47

/************************************************************************
 *									*
 * Wrappers around libxml2 XPath specific functions			*
 *									*
 ************************************************************************/

48 49 50 51 52 53 54 55 56 57 58
/**
 * virXPathString:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 *
 * Convenience function to evaluate an XPath string
 *
 * Returns a new string which must be deallocated by the caller or NULL
 *         if the evaluation failed.
 */
char *
59
virXPathString(const char *xpath,
60
               xmlXPathContextPtr ctxt)
61
{
62
    xmlXPathObjectPtr obj;
63
    xmlNodePtr relnode;
64 65 66
    char *ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
67
        virXMLError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
68
                    "%s", _("Invalid parameter to virXPathString()"));
69
        return (NULL);
70
    }
71
    relnode = ctxt->node;
72
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
73
    ctxt->node = relnode;
74
    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
D
Daniel P. Berrange 已提交
75
        (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
76
        xmlXPathFreeObject(obj);
77
        return (NULL);
D
Daniel P. Berrange 已提交
78
    }
79 80 81
    ret = strdup((char *) obj->stringval);
    xmlXPathFreeObject(obj);
    if (ret == NULL) {
82
        virReportOOMError();
83
    }
84
    return (ret);
85 86
}

87 88 89 90 91 92 93 94 95 96 97 98 99
/**
 * virXPathStringLimit:
 * @xpath: the XPath string to evaluate
 * @maxlen: maximum length permittred string
 * @ctxt: an XPath context
 *
 * Wrapper for virXPathString, which validates the length of the returned
 * string.
 *
 * Returns a new string which must be deallocated by the caller or NULL if
 * the evaluation failed.
 */
char *
100
virXPathStringLimit(const char *xpath,
101 102 103
                    size_t maxlen,
                    xmlXPathContextPtr ctxt)
{
104
    char *tmp = virXPathString(xpath, ctxt);
105 106

    if (tmp != NULL && strlen(tmp) >= maxlen) {
107
        virXMLError(VIR_ERR_INTERNAL_ERROR,
E
Eric Blake 已提交
108
                    _("\'%s\' value longer than %zd bytes in virXPathStringLimit()"),
109 110 111 112 113 114 115
                    xpath, maxlen);
            return NULL;
    }

    return tmp;
}

116 117 118 119 120 121 122 123 124 125 126 127
/**
 * virXPathNumber:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned double value
 *
 * Convenience function to evaluate an XPath number
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the evaluation failed.
 */
int
128
virXPathNumber(const char *xpath,
129 130
               xmlXPathContextPtr ctxt,
               double *value)
131
{
132
    xmlXPathObjectPtr obj;
133
    xmlNodePtr relnode;
134 135

    if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
136
        virXMLError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
137
                    "%s", _("Invalid parameter to virXPathNumber()"));
138
        return (-1);
139
    }
140
    relnode = ctxt->node;
141
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
142
    ctxt->node = relnode;
143 144
    if ((obj == NULL) || (obj->type != XPATH_NUMBER) ||
        (isnan(obj->floatval))) {
145 146
        xmlXPathFreeObject(obj);
        return (-1);
147
    }
148

149 150
    *value = obj->floatval;
    xmlXPathFreeObject(obj);
151
    return (0);
152 153
}

154
static int
155
virXPathLongBase(const char *xpath,
156 157 158
                 xmlXPathContextPtr ctxt,
                 int base,
                 long *value)
159
{
160
    xmlXPathObjectPtr obj;
161
    xmlNodePtr relnode;
162 163 164
    int ret = 0;

    if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
165
        virXMLError(VIR_ERR_INTERNAL_ERROR,
166
                    "%s", _("Invalid parameter to virXPathLong()"));
167
        return (-1);
168
    }
169
    relnode = ctxt->node;
170
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
171
    ctxt->node = relnode;
172 173 174
    if ((obj != NULL) && (obj->type == XPATH_STRING) &&
        (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
        char *conv = NULL;
175
        long val;
176

177
        val = strtol((const char *) obj->stringval, &conv, base);
178
        if (conv == (const char *) obj->stringval) {
179 180
            ret = -2;
        } else {
181 182
            *value = val;
        }
183 184
    } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
               (!(isnan(obj->floatval)))) {
185 186 187 188
        *value = (long) obj->floatval;
        if (*value != obj->floatval) {
            ret = -2;
        }
189
    } else {
190
        ret = -1;
191
    }
192

193
    xmlXPathFreeObject(obj);
194
    return (ret);
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
/**
 * virXPathInt:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned int value
 *
 * Convenience function to evaluate an XPath number
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the XPath evaluation failed or -2 if the
 *         value doesn't have an int format.
 */
int
virXPathInt(const char *xpath,
            xmlXPathContextPtr ctxt,
            int *value)
{
    long tmp;
    int ret;

    ret = virXPathLongBase(xpath, ctxt, 10, &tmp);
    if (ret < 0)
        return ret;
    if ((int) tmp != tmp)
        return -2;
    *value = tmp;
    return 0;
}

226
/**
227
 * virXPathLong:
228 229 230 231 232 233 234 235 236 237 238
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned long value
 *
 * Convenience function to evaluate an XPath number
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the XPath evaluation failed or -2 if the
 *         value doesn't have a long format.
 */
int
239
virXPathLong(const char *xpath,
240 241 242
             xmlXPathContextPtr ctxt,
             long *value)
{
243
    return virXPathLongBase(xpath, ctxt, 10, value);
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
}

/**
 * virXPathLongHex:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned long value
 *
 * Convenience function to evaluate an XPath number
 * according to a base of 16
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the XPath evaluation failed or -2 if the
 *         value doesn't have a long format.
 */
int
260
virXPathLongHex(const char *xpath,
261 262 263
                xmlXPathContextPtr ctxt,
                long *value)
{
264
    return virXPathLongBase(xpath, ctxt, 16, value);
265 266 267
}

static int
268
virXPathULongBase(const char *xpath,
269 270 271
                  xmlXPathContextPtr ctxt,
                  int base,
                  unsigned long *value)
272 273 274 275 276 277
{
    xmlXPathObjectPtr obj;
    xmlNodePtr relnode;
    int ret = 0;

    if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
278
        virXMLError(VIR_ERR_INTERNAL_ERROR,
279
                    "%s", _("Invalid parameter to virXPathULong()"));
280 281 282 283
        return (-1);
    }
    relnode = ctxt->node;
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
284
    ctxt->node = relnode;
285 286 287 288 289
    if ((obj != NULL) && (obj->type == XPATH_STRING) &&
        (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
        char *conv = NULL;
        long val;

290
        val = strtoul((const char *) obj->stringval, &conv, base);
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
        if (conv == (const char *) obj->stringval) {
            ret = -2;
        } else {
            *value = val;
        }
    } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
               (!(isnan(obj->floatval)))) {
        *value = (unsigned long) obj->floatval;
        if (*value != obj->floatval) {
            ret = -2;
        }
    } else {
        ret = -1;
    }

    xmlXPathFreeObject(obj);
    return (ret);
}

310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
/**
 * virXPathUInt:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned int value
 *
 * Convenience function to evaluate an XPath number
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the XPath evaluation failed or -2 if the
 *         value doesn't have an int format.
 */
int
virXPathUInt(const char *xpath,
             xmlXPathContextPtr ctxt,
             unsigned int *value)
{
    unsigned long tmp;
    int ret;

    ret = virXPathULongBase(xpath, ctxt, 10, &tmp);
    if (ret < 0)
        return ret;
    if ((unsigned int) tmp != tmp)
        return -2;
    *value = tmp;
    return 0;
}

339 340 341 342 343 344 345 346 347 348 349 350 351
/**
 * virXPathULong:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned long value
 *
 * Convenience function to evaluate an XPath number
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the XPath evaluation failed or -2 if the
 *         value doesn't have a long format.
 */
int
352
virXPathULong(const char *xpath,
353 354 355
              xmlXPathContextPtr ctxt,
              unsigned long *value)
{
356
    return virXPathULongBase(xpath, ctxt, 10, value);
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
}

/**
 * virXPathUHex:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned long value
 *
 * Convenience function to evaluate an XPath number
 * according to base of 16
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the XPath evaluation failed or -2 if the
 *         value doesn't have a long format.
 */
int
373
virXPathULongHex(const char *xpath,
374 375 376
                 xmlXPathContextPtr ctxt,
                 unsigned long *value)
{
377
    return virXPathULongBase(xpath, ctxt, 16, value);
378 379
}

M
Mark McLoughlin 已提交
380 381 382 383 384 385 386 387 388 389 390 391 392
/**
 * virXPathULongLong:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned long long value
 *
 * Convenience function to evaluate an XPath number
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the XPath evaluation failed or -2 if the
 *         value doesn't have a long format.
 */
int
393
virXPathULongLong(const char *xpath,
M
Mark McLoughlin 已提交
394 395 396 397 398 399 400 401
                  xmlXPathContextPtr ctxt,
                  unsigned long long *value)
{
    xmlXPathObjectPtr obj;
    xmlNodePtr relnode;
    int ret = 0;

    if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
402
        virXMLError(VIR_ERR_INTERNAL_ERROR,
M
Mark McLoughlin 已提交
403 404 405 406 407
                    "%s", _("Invalid parameter to virXPathULong()"));
        return (-1);
    }
    relnode = ctxt->node;
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
408
    ctxt->node = relnode;
M
Mark McLoughlin 已提交
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
    if ((obj != NULL) && (obj->type == XPATH_STRING) &&
        (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
        char *conv = NULL;
        unsigned long long val;

        val = strtoull((const char *) obj->stringval, &conv, 10);
        if (conv == (const char *) obj->stringval) {
            ret = -2;
        } else {
            *value = val;
        }
    } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
               (!(isnan(obj->floatval)))) {
        *value = (unsigned long long) obj->floatval;
        if (*value != obj->floatval) {
            ret = -2;
        }
    } else {
        ret = -1;
    }

    xmlXPathFreeObject(obj);
    return (ret);
}

434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
/**
 * virXPathULongLong:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned long long value
 *
 * Convenience function to evaluate an XPath number
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the XPath evaluation failed or -2 if the
 *         value doesn't have a long format.
 */
int
virXPathLongLong(const char *xpath,
                 xmlXPathContextPtr ctxt,
                 long long *value)
{
    xmlXPathObjectPtr obj;
    xmlNodePtr relnode;
    int ret = 0;

    if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
        virXMLError(VIR_ERR_INTERNAL_ERROR,
                    "%s", _("Invalid parameter to virXPathLongLong()"));
        return (-1);
    }
    relnode = ctxt->node;
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
    ctxt->node = relnode;
    if ((obj != NULL) && (obj->type == XPATH_STRING) &&
        (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
        char *conv = NULL;
        unsigned long long val;

        val = strtoll((const char *) obj->stringval, &conv, 10);
        if (conv == (const char *) obj->stringval) {
            ret = -2;
        } else {
            *value = val;
        }
    } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
               (!(isnan(obj->floatval)))) {
        *value = (long long) obj->floatval;
        if (*value != obj->floatval) {
            ret = -2;
        }
    } else {
        ret = -1;
    }

    xmlXPathFreeObject(obj);
    return (ret);
}

488 489 490 491 492 493 494
char *
virXMLPropString(xmlNodePtr node,
                 const char *name)
{
    return (char *)xmlGetProp(node, BAD_CAST name);
}

495 496 497 498 499 500 501 502 503 504
/**
 * virXPathBoolean:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 *
 * Convenience function to evaluate an XPath boolean
 *
 * Returns 0 if false, 1 if true, or -1 if the evaluation failed.
 */
int
505
virXPathBoolean(const char *xpath,
506
                xmlXPathContextPtr ctxt)
507
{
508
    xmlXPathObjectPtr obj;
509
    xmlNodePtr relnode;
510 511 512
    int ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
513
        virXMLError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
514
                    "%s", _("Invalid parameter to virXPathBoolean()"));
515
        return (-1);
516
    }
517
    relnode = ctxt->node;
518
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
519
    ctxt->node = relnode;
520 521
    if ((obj == NULL) || (obj->type != XPATH_BOOLEAN) ||
        (obj->boolval < 0) || (obj->boolval > 1)) {
522 523
        xmlXPathFreeObject(obj);
        return (-1);
524 525
    }
    ret = obj->boolval;
526

527
    xmlXPathFreeObject(obj);
528
    return (ret);
529 530 531 532 533 534 535 536 537 538 539 540 541
}

/**
 * virXPathNode:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 *
 * Convenience function to evaluate an XPath node set and returning
 * only one node, the first one in the set if any
 *
 * Returns a pointer to the node or NULL if the evaluation failed.
 */
xmlNodePtr
542
virXPathNode(const char *xpath,
543
             xmlXPathContextPtr ctxt)
544
{
545
    xmlXPathObjectPtr obj;
546
    xmlNodePtr relnode;
547 548 549
    xmlNodePtr ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
550
        virXMLError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
551
                    "%s", _("Invalid parameter to virXPathNode()"));
552
        return (NULL);
553
    }
554
    relnode = ctxt->node;
555
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
556
    ctxt->node = relnode;
557 558
    if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
        (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) ||
559 560 561
        (obj->nodesetval->nodeTab == NULL)) {
        xmlXPathFreeObject(obj);
        return (NULL);
562
    }
563

564 565
    ret = obj->nodesetval->nodeTab[0];
    xmlXPathFreeObject(obj);
566
    return (ret);
567
}
568

569 570 571 572 573 574 575 576 577 578 579 580
/**
 * virXPathNodeSet:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @list: the returned list of nodes (or NULL if only count matters)
 *
 * Convenience function to evaluate an XPath node set
 *
 * Returns the number of nodes found in which case @list is set (and
 *         must be freed) or -1 if the evaluation failed.
 */
int
581
virXPathNodeSet(const char *xpath,
582 583
                xmlXPathContextPtr ctxt,
                xmlNodePtr **list)
584
{
585
    xmlXPathObjectPtr obj;
586
    xmlNodePtr relnode;
587 588 589
    int ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
590
        virXMLError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
591
                    "%s", _("Invalid parameter to virXPathNodeSet()"));
592
        return (-1);
593
    }
594 595 596 597

    if (list != NULL)
        *list = NULL;

598
    relnode = ctxt->node;
599
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
600
    ctxt->node = relnode;
D
Daniel Veillard 已提交
601 602 603
    if (obj == NULL)
        return(0);
    if (obj->type != XPATH_NODESET) {
604 605
        xmlXPathFreeObject(obj);
        return (-1);
606
    }
D
Daniel Veillard 已提交
607 608 609 610
    if ((obj->nodesetval == NULL)  || (obj->nodesetval->nodeNr < 0)) {
        xmlXPathFreeObject(obj);
        return (0);
    }
611

612
    ret = obj->nodesetval->nodeNr;
613
    if (list != NULL && ret) {
614
        if (VIR_ALLOC_N(*list, ret) < 0) {
615
            virReportOOMError();
616
            ret = -1;
617 618 619 620
        } else {
            memcpy(*list, obj->nodesetval->nodeTab,
                   ret * sizeof(xmlNodePtr));
        }
621 622
    }
    xmlXPathFreeObject(obj);
623
    return (ret);
624
}
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753


/**
 * catchXMLError:
 *
 * Called from SAX on parsing errors in the XML.
 */
static void
catchXMLError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
{
    int domcode = VIR_FROM_XML;
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;

    if (ctxt) {
        if (ctxt->_private)
            domcode = ((struct virParserData *) ctxt->_private)->domcode;

        if (virGetLastError() == NULL &&
            ctxt->lastError.level == XML_ERR_FATAL &&
            ctxt->lastError.message != NULL) {
            virGenericReportError(domcode, VIR_ERR_XML_DETAIL,
                                  _("at line %d: %s"),
                                  ctxt->lastError.line,
                                  ctxt->lastError.message);
        }
    }
}


/**
 * virXMLParseHelper:
 * @domcode: error domain of the caller, usually VIR_FROM_THIS
 * @filename: file to be parsed or NULL if string parsing is requested
 * @xmlStr: XML string to be parsed in case filename is NULL
 * @url: URL of XML document for string parser
 *
 * Parse XML document provided either as a file or a string. The function
 * guarantees that the XML document contains a root element.
 *
 * Returns parsed XML document.
 */
xmlDocPtr
virXMLParseHelper(int domcode,
                  const char *filename,
                  const char *xmlStr,
                  const char *url)
{
    struct virParserData private;
    xmlParserCtxtPtr pctxt;
    xmlDocPtr xml = NULL;

    /* Set up a parser context so we can catch the details of XML errors. */
    pctxt = xmlNewParserCtxt();
    if (!pctxt || !pctxt->sax)
        goto error;

    private.domcode = domcode;
    pctxt->_private = &private;
    pctxt->sax->error = catchXMLError;

    if (filename) {
        xml = xmlCtxtReadFile(pctxt, filename, NULL,
                              XML_PARSE_NOENT | XML_PARSE_NONET |
                              XML_PARSE_NOWARNING);
    } else {
        xml = xmlCtxtReadDoc(pctxt, BAD_CAST xmlStr, url, NULL,
                             XML_PARSE_NOENT | XML_PARSE_NONET |
                             XML_PARSE_NOWARNING);
    }
    if (!xml)
        goto error;

    if (xmlDocGetRootElement(xml) == NULL) {
        virGenericReportError(domcode, VIR_ERR_INTERNAL_ERROR,
                              "%s", _("missing root element"));
        goto error;
    }

cleanup:
    xmlFreeParserCtxt(pctxt);

    return xml;

error:
    xmlFreeDoc(xml);
    xml = NULL;

    if (virGetLastError() == NULL) {
        virGenericReportError(domcode, VIR_ERR_XML_ERROR,
                              "%s", _("failed to parse xml document"));
    }
    goto cleanup;
}

/**
 * virXMLParseStrHelper:
 * @domcode: error domain of the caller, usually VIR_FROM_THIS
 * @xmlStr: XML string to be parsed in case filename is NULL
 * @url: URL of XML document for string parser
 *
 * Parse XML document provided as a string. The function guarantees that
 * the XML document contains a root element.
 *
 * Returns parsed XML document.
 */
xmlDocPtr
virXMLParseStrHelper(int domcode,
                     const char *xmlStr,
                     const char *url)
{
    return virXMLParseHelper(domcode, NULL, xmlStr, url);
}

/**
 * virXMLParseFileHelper:
 * @domcode: error domain of the caller, usually VIR_FROM_THIS
 * @filename: file to be parsed
 *
 * Parse XML document provided as a file. The function guarantees that
 * the XML document contains a root element.
 *
 * Returns parsed XML document.
 */
xmlDocPtr
virXMLParseFileHelper(int domcode,
                      const char *filename)
{
    return virXMLParseHelper(domcode, filename, NULL, NULL);
}