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.



122
123
124
125
126
127
128
129
130
131
132
# File 'lib/leptris/xml/serialization.rb', line 122

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.



78
79
80
81
82
83
# File 'lib/leptris/xml/serialization.rb', line 78

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

.escape_text(string) ⇒ Object



94
95
96
# File 'lib/leptris/xml/serialization.rb', line 94

def self.escape_text(string)
  string.gsub(ESCAPE_TEXT_RE, ESCAPE_TEXT)
end

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

ffi_function is a bound _serialize_into function. The buffer cycle lives at the FFI seam (FFI.serialize_into_string); this module owns only options selection and construction.



24
25
26
27
28
29
30
31
32
33
34
# File 'lib/leptris/xml/serialization.rb', line 24

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
  Leptris::XML::FFI.serialize_into_string(ffi_function, c_ptr, opts.pointer)
end

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



47
48
49
50
51
52
53
# File 'lib/leptris/xml/serialization.rb', line 47

def self.to_xml_display(c_ptr, indent: 0, no_decl: false, encoding: nil)
  opts, encoding_anchor = build_options(
    indent: indent, no_decl: no_decl, encoding: encoding)
  str_ptr = Leptris::XML::FFI.leptris_document_serialize_ext_sized(
    c_ptr, opts.pointer, INDENT_TEXT_EXT.pointer, INDENT_TEXT_EXT.size)
  Leptris::XML::FFI.read_owned_string(str_ptr)
end

.to_xml_element_unit(element, unit, indent: 0) ⇒ Object

Element-face indent unit (leptris-ruby#109 residual 2): no element-level ext-serialize entry exists yet, so the unit path copies the element into a fresh document (C-side copy, one pool allocation), serializes that document without a declaration, and returns the subtree — identical output to the element serializer for the standard layout, with the unit.



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/leptris/xml/serialization.rb', line 104

def self.to_xml_element_unit(element, unit, indent: 0)
  document = Leptris::XML::Document.create
  begin
    copy_ptr = Leptris::XML::FFI.leptris_element_copy(
      element.c_ptr, document.c_ptr)
    if copy_ptr.null?
      raise Leptris::XML::Error, "leptris_element_copy failed"
    end
    document.root = Leptris::XML::Node.wrap(copy_ptr, document)
    to_xml_indent_unit(document.c_ptr, unit,
                       indent: indent, no_decl: true)
  ensure
    document.free
  end
end

.to_xml_indent_unit(c_ptr, unit, indent: 0, no_decl: false, encoding: nil) ⇒ Object

Indent-unit serialization (libleptris 1.9.22, #633 — leptris-ruby#109): Nokogiri's indent_text semantics — the unit string replaces the default spaces, repeated indent times per depth level, standard layout otherwise. The engine emits ONE copy of the unit string per level (options->indent is ignored when a unit is set), so the binding multiplies unit x indent to reach Nokogiri's repeat count.



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

def self.to_xml_indent_unit(c_ptr, unit, indent: 0, no_decl: false,
                            encoding: nil)
  opts, encoding_anchor = build_options(
    indent: indent, no_decl: no_decl, encoding: encoding)
  ext = Leptris::XML::FFI::SerializeExtStruct.new
  unit_anchor = ::FFI::MemoryPointer.from_string(
    indent.positive? ? unit.to_s * indent : unit.to_s)
  ext[:indent_unit] = unit_anchor
  str_ptr = Leptris::XML::FFI.leptris_document_serialize_ext_sized(
    c_ptr, opts.pointer, ext.pointer, ext.size)
  Leptris::XML::FFI.read_owned_string(str_ptr)
end