Class: Canon::Xml::C14n

Inherits:
Object
  • Object
show all
Defined in:
lib/canon/xml/c14n.rb

Overview

XML Canonicalization 1.1 implementation Per W3C Recommendation: www.w3.org/TR/xml-c14n11/

Class Method Summary collapse

Class Method Details

.canonicalize(xml, with_comments: false) ⇒ String

Canonicalize an XML document

Parameters:

  • xml (String)

    XML document as string

  • with_comments (Boolean) (defaults to: false)

    Include comments in canonical form

Returns:

  • (String)

    Canonical form in UTF-8



16
17
18
19
20
21
22
23
# File 'lib/canon/xml/c14n.rb', line 16

def self.canonicalize(xml, with_comments: false)
  # Build XPath data model
  root_node = DataModel.from_xml(xml)

  # Process to canonical form
  processor = Processor.new(with_comments: with_comments)
  processor.process(root_node)
end

.canonicalize_subset(xml, xpath, with_comments: false) ⇒ String

Canonicalize a document subset selected by XPath expression.

Implements W3C C14N 1.1 subset canonicalization:

  1. Evaluates XPath against the document tree

  2. Marks matched nodes as the node-set

  3. Renders canonical form for only the selected nodes, with namespace and attribute inheritance from excluded ancestors

Parameters:

  • xml (String)

    XML document as string

  • xpath (String)

    XPath expression for subset selection

  • with_comments (Boolean) (defaults to: false)

    Include comments in canonical form

Returns:

  • (String)

    Canonical form in UTF-8



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/canon/xml/c14n.rb', line 37

def self.canonicalize_subset(xml, xpath, with_comments: false)
  root_node = DataModel.from_xml(xml)

  # Mark all nodes as NOT in the node-set initially
  mark_all_nodes(root_node, false)

  # Evaluate XPath and mark matched nodes
  matched = XPathEngine.evaluate(root_node, xpath)

  # If XPath matches root or is empty, fall back to full canonicalization
  if matched.empty?
    mark_all_nodes(root_node, true)
  else
    # Mark matched nodes and their ancestors/descendants
    mark_subset(root_node, matched)
  end

  # Process to canonical form
  processor = Processor.new(with_comments: with_comments)
  processor.process(root_node)
end