|
58 | 58 | #include <libxml/xmlwriter.h> |
59 | 59 | #include <libxml/xpath.h> |
60 | 60 | #include <libxml/xpathInternals.h> |
| 61 | +#include <libxml/c14n.h> |
61 | 62 |
|
62 | 63 | /* |
63 | 64 | * We used to check for xmlStructuredErrorContext via a configure test; but |
@@ -565,6 +566,86 @@ xmltext(PG_FUNCTION_ARGS) |
565 | 566 | #endif /* not USE_LIBXML */ |
566 | 567 | } |
567 | 568 |
|
| 569 | +/* |
| 570 | + * Canonicalizes the given XML document according to the W3C Canonical XML 1.1 |
| 571 | + * specification, using libxml2's xmlC14NDocDumpMemory(). |
| 572 | + * |
| 573 | + * The input XML must be a well-formed document (not a fragment). The |
| 574 | + * canonical form is deterministic and useful for digital signatures and |
| 575 | + * comparing logically equivalent XML. |
| 576 | + * |
| 577 | + * The second argument determines whether comments are preserved |
| 578 | + * (true) or omitted (false) in the canonicalized output. |
| 579 | + */ |
| 580 | +Datum xmlcanonicalize(PG_FUNCTION_ARGS) |
| 581 | +{ |
| 582 | +#ifdef USE_LIBXML |
| 583 | + xmltype *arg = PG_GETARG_XML_P(0); |
| 584 | + bool keep_comments = PG_GETARG_BOOL(1); |
| 585 | + text *result; |
| 586 | + volatile xmlChar *xmlbuf = NULL; |
| 587 | + volatile int nbytes = 0; |
| 588 | + volatile xmlDocPtr doc = NULL; |
| 589 | + PgXmlErrorContext *xmlerrcxt; |
| 590 | + |
| 591 | + /* Set up XML error context for proper libxml2 error integration */ |
| 592 | + xmlerrcxt = pg_xml_init(PG_XML_STRICTNESS_ALL); |
| 593 | + |
| 594 | + PG_TRY(); |
| 595 | + { |
| 596 | + /* Parse the input as a full XML document */ |
| 597 | + doc = xml_parse(arg, XMLOPTION_DOCUMENT, false, |
| 598 | + GetDatabaseEncoding(), NULL, NULL, (Node *)xmlerrcxt); |
| 599 | + |
| 600 | + /* |
| 601 | + * xmlC14NDocDumpMemory arguments: |
| 602 | + * - doc: the XML document to canonicalize (already parsed above) |
| 603 | + * - nodes: NULL means the entire document is canonicalized |
| 604 | + * - mode: 2 selects the Canonical XML 1.1 algorithm (xmlC14NMode enum) |
| 605 | + * - inclusive_ns_prefixes: NULL includes all namespaces by default |
| 606 | + * - with_comments: determined by keep_comments argument |
| 607 | + * - doc_txt_ptr: output buffer receiving the canonicalized XML (xmlbuf) |
| 608 | + * |
| 609 | + * On success, xmlbuf points to the serialized canonical form, and nbytes |
| 610 | + * holds its size. |
| 611 | + */ |
| 612 | + nbytes = xmlC14NDocDumpMemory(doc, |
| 613 | + NULL, /* entire document */ |
| 614 | + 2, /* xmlC14NMode 1.1 */ |
| 615 | + NULL, /* all namespaces */ |
| 616 | + keep_comments, |
| 617 | + (xmlChar **)&xmlbuf); |
| 618 | + |
| 619 | + if (nbytes < 0 || xmlbuf == NULL || xmlerrcxt->err_occurred) |
| 620 | + xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR, |
| 621 | + "could not canonicalize XML document"); |
| 622 | + |
| 623 | + result = cstring_to_text_with_len((const char *)xmlbuf, nbytes); |
| 624 | + } |
| 625 | + PG_CATCH(); |
| 626 | + { |
| 627 | + if (doc) |
| 628 | + xmlFreeDoc((xmlDocPtr)doc); |
| 629 | + if (xmlbuf) |
| 630 | + xmlFree((xmlChar *)xmlbuf); |
| 631 | + |
| 632 | + pg_xml_done(xmlerrcxt, true); |
| 633 | + PG_RE_THROW(); |
| 634 | + } |
| 635 | + PG_END_TRY(); |
| 636 | + |
| 637 | + if (doc) |
| 638 | + xmlFreeDoc((xmlDocPtr)doc); |
| 639 | + if (xmlbuf) |
| 640 | + xmlFree((xmlChar *)xmlbuf); |
| 641 | + pg_xml_done(xmlerrcxt, false); |
| 642 | + |
| 643 | + PG_RETURN_XML_P(result); |
| 644 | +#else |
| 645 | + NO_XML_SUPPORT(); |
| 646 | + return 0; |
| 647 | +#endif /* not USE_LIBXML */ |
| 648 | +} |
568 | 649 |
|
569 | 650 | /* |
570 | 651 | * TODO: xmlconcat needs to merge the notations and unparsed entities |
|
0 commit comments