Class: Lutaml::Xml::Builder::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/lutaml/xml/builder/base.rb

Overview

Base builder for XML construction using moxml. All adapter-specific builders inherit from this class.

Direct Known Subclasses

Nokogiri, Oga, Ox, Rexml

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(doc, context, options = {}) ⇒ Base

Returns a new instance of Base.



29
30
31
32
33
34
# File 'lib/lutaml/xml/builder/base.rb', line 29

def initialize(doc, context, options = {})
  @doc = doc
  @context = context
  @encoding = options[:encoding]
  @current_stack = [doc]
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args) ⇒ Object



151
152
153
154
# File 'lib/lutaml/xml/builder/base.rb', line 151

def method_missing(method_name, *args, &)
  attrs = args.first.is_a?(Hash) ? args.first : {}
  create_and_add_element(method_name.to_s, attributes: attrs, &)
end

Instance Attribute Details

#docObject (readonly)

Returns the value of attribute doc.



27
28
29
# File 'lib/lutaml/xml/builder/base.rb', line 27

def doc
  @doc
end

#encodingObject (readonly)

Returns the value of attribute encoding.



27
28
29
# File 'lib/lutaml/xml/builder/base.rb', line 27

def encoding
  @encoding
end

Class Method Details

.build(options = {}) {|instance| ... } ⇒ Object

Yields:

  • (instance)


11
12
13
14
15
16
17
18
19
20
# File 'lib/lutaml/xml/builder/base.rb', line 11

def self.build(options = {})
  context = Moxml.new(moxml_backend)
  if Lutaml::Model::RuntimeCompatibility.opal?
    context.config.namespace_validation_mode = :lenient
  end
  doc = context.create_document
  instance = new(doc, context, options)
  yield(instance) if block_given?
  instance
end

.moxml_backendObject

Override in subclass to set the moxml backend



23
24
25
# File 'lib/lutaml/xml/builder/base.rb', line 23

def self.moxml_backend
  nil
end

Instance Method Details

#add_cdata(element, value) ⇒ Object



81
82
83
# File 'lib/lutaml/xml/builder/base.rb', line 81

def add_cdata(element, value)
  resolve_target(element).add_child(@doc.create_cdata(value.to_s))
end

#add_comment(element_or_text, text = nil) ⇒ Object



85
86
87
88
89
90
91
92
93
94
# File 'lib/lutaml/xml/builder/base.rb', line 85

def add_comment(element_or_text, text = nil)
  if text.nil?
    target = current_element
    comment_text = element_or_text
  else
    target = resolve_target(element_or_text)
    comment_text = text
  end
  target.add_child(@doc.create_comment(comment_text.to_s))
end

#add_processing_instruction(target, content) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/lutaml/xml/builder/base.rb', line 96

def add_processing_instruction(target, content)
  pi = @doc.create_processing_instruction(target.to_s, content.to_s)
  if current_element.is_a?(Moxml::Document)
    # Add before root element or at end if no root
    root_node = current_element.root
    if root_node
      root_node.add_previous_sibling(pi)
    else
      current_element.add_child(pi)
    end
  else
    current_element.add_child(pi)
  end
  pi
end

#add_text(element, text_content, cdata: false) ⇒ Object



75
76
77
78
79
# File 'lib/lutaml/xml/builder/base.rb', line 75

def add_text(element, text_content, cdata: false)
  return add_cdata(element, text_content) if cdata

  resolve_target(element).add_child(@doc.create_text(text_content.to_s))
end

#add_xml_fragment(element, content) ⇒ Object



67
68
69
70
71
72
73
# File 'lib/lutaml/xml/builder/base.rb', line 67

def add_xml_fragment(element, content)
  target = resolve_target(element)
  parsed = @context.parse("<__root__>#{content}</__root__>")
  parsed.root&.children&.each { |child| target.add_child(child) }
rescue Moxml::ParseError
  target.add_child(@doc.create_text(content.to_s))
end

#cdata(content) ⇒ Object



116
117
118
# File 'lib/lutaml/xml/builder/base.rb', line 116

def cdata(content)
  add_cdata(current_element, content)
end

#create_and_add_element(element_name, prefix: (prefix_unset = true nil), attributes: {}, blank_xmlns: false) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/lutaml/xml/builder/base.rb', line 49

def create_and_add_element(
  element_name,
  prefix: (prefix_unset = true
           nil),
  attributes: {},
  blank_xmlns: false
)
  element_name = element_name.first if element_name.is_a?(Array)

  new_el = @doc.create_element(element_name)
  apply_attributes(new_el, attributes, blank_xmlns)
  resolve_namespace(new_el, prefix, prefix_unset)
  attach_to_parent(new_el, prefix, prefix_unset)
  with_element_context(new_el) { yield(self) } if block_given?

  new_el
end

#current_elementObject Also known as: current_node



36
37
38
# File 'lib/lutaml/xml/builder/base.rb', line 36

def current_element
  @current_stack.last
end

#parentObject



45
46
47
# File 'lib/lutaml/xml/builder/base.rb', line 45

def parent
  current_element
end

#respond_to_missing?(_method_name, _include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


156
157
158
# File 'lib/lutaml/xml/builder/base.rb', line 156

def respond_to_missing?(_method_name, _include_private = false)
  true
end

#text(content) ⇒ Object



112
113
114
# File 'lib/lutaml/xml/builder/base.rb', line 112

def text(content)
  add_text(current_element, content)
end

#to_sObject



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/lutaml/xml/builder/base.rb', line 120

def to_s
  return "" unless @doc.root

  # Serialize full document content (including PIs before root)
  # Check if there are any nodes before the root element
  doc_children = @doc.children
  has_pi_or_comment = doc_children.any? do |child|
    child.is_a?(Moxml::ProcessingInstruction) || child.is_a?(Moxml::Comment)
  end

  if has_pi_or_comment
    # Serialize each top-level node individually
    parts = doc_children.map do |child|
      if child == @doc.root
        child.to_xml(declaration: false, expand_empty: false)
      else
        child.to_xml
      end
    end
    parts.join("\n")
  else
    @doc.root.to_xml(declaration: false, expand_empty: false)
  end
end

#to_xmlObject



145
146
147
148
149
# File 'lib/lutaml/xml/builder/base.rb', line 145

def to_xml
  result = to_s
  result = result.encode(encoding) if encoding && result.encoding.to_s != encoding
  result
end

#xmlObject



41
42
43
# File 'lib/lutaml/xml/builder/base.rb', line 41

def xml
  self
end