Module: Leptris::XML::Serialization

Defined in:
lib/leptris/xml/serialization.rb

Overview

Owns the SerializeOptions lifecycle and the owned-string read for document and subtree serialization/canonicalization. Document and Element expose one-line methods over this module — the options struct, the encoding anchor, the C call, and the read-and-free all live here.

Class Method Summary collapse

Class Method Details

.build_options(indent: 0, no_decl: false, encoding: nil) ⇒ Object

Builds a SerializeOptions struct. Returns [opts, encoding_anchor]; the anchor must stay referenced while opts is in an FFI call.



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/leptris/xml/serialization.rb', line 62

def self.build_options(indent: 0, no_decl: false, encoding: nil)
  opts = Leptris::XML::FFI::SerializeOptions.new
  opts[:indent] = indent.to_i
  opts[:xml_declaration] = no_decl ? 0 : 1
  encoding_anchor = nil
  if encoding
    encoding_anchor = ::FFI::MemoryPointer.from_string(encoding.to_s)
    opts[:encoding] = encoding_anchor
  end
  [opts, encoding_anchor]
end

.canonicalize(ffi_function, c_ptr, version:, mode:, inclusive_namespaces: nil, with_comments: false) ⇒ Object

ffi_function is a bound FFI function taking (c_ptr, version, mode, ns_ptr, flags): leptris_c14n_canonicalize_ex or leptris_c14n_canonicalize_subtree_ex.



53
54
55
56
57
58
# File 'lib/leptris/xml/serialization.rb', line 53

def self.canonicalize(ffi_function, c_ptr, version:, mode:,
                      inclusive_namespaces: nil, with_comments: false)
  ns_ptr, _ns_anchor = Leptris::XML::CStringArray.to_c(inclusive_namespaces)
  str_ptr = ffi_function.call(c_ptr, version, mode, ns_ptr, with_comments ? 1 : 0)
  Leptris::XML::FFI.read_owned_string(str_ptr)
end

.to_xml(ffi_function, c_ptr, indent: 0, no_decl: false, encoding: nil) ⇒ Object

ffi_function is a bound _serialize_into function taking (c_ptr, buf, capacity, out_len, opts): size query with buf=NULL, then one fill into a caller buffer. Since libleptris 1.9.0 the pair reuses a single serialization through a per-document cache (leptris#541) — no C-side result-string allocation, and repeated serializations of an unmutated document skip the serialize pass.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/leptris/xml/serialization.rb', line 27

def self.to_xml(ffi_function, c_ptr, indent: 0, no_decl: false, encoding: nil)
  opts =
    if indent.to_i.zero? && !no_decl && encoding.nil?
      DEFAULT_OPTIONS
    else
      opts, _encoding_anchor = build_options(
        indent: indent, no_decl: no_decl, encoding: encoding)
      opts
    end
  need = ffi_function.call(c_ptr, nil, 0, nil, opts.pointer)
  return "" if need.zero?
  buf = ::FFI::MemoryPointer.new(:char, need)
  begin
    ffi_function.call(c_ptr, buf, need, nil, opts.pointer)
    # The buffer holds exactly the serialization + NUL; XML output
    # is NUL-free, so a bounded read_string is exact. (Avoids the
    # out_len param — no portable size_t read exists on Pointer.)
    buf.read_string
  ensure
    buf.free
  end
end