Class: Tilia::Xml::Writer

Inherits:
Object
  • Object
show all
Includes:
ContextStackTrait
Defined in:
lib/tilia/xml/writer.rb

Overview

The XML Writer class.

This class works exactly as PHP’s built-in XMLWriter, with a few additions.

Namespaces can be registered beforehand, globally. When the first element is written, namespaces will automatically be declared.

The write_attribute, startElement and write_element can now take a clark-notation element name (example: http://www.w3.org/2005/Atomlink).

If, when writing the namespace is a known one a prefix will automatically be selected, otherwise a random prefix will be generated.

Instead of standard string values, the writer can take Element classes (as defined by this library) to delegate the serialization.

The write() method can take array structures to quickly write out simple xml trees.

Instance Attribute Summary

Attributes included from ContextStackTrait

#class_map, #context_uri, #element_map, #namespace_map

Instance Method Summary collapse

Methods included from ContextStackTrait

#pop_context, #push_context

Constructor Details

#initializeWriter

Initializes the instance variables



184
185
186
187
188
189
# File 'lib/tilia/xml/writer.rb', line 184

def initialize
  @adhoc_namespaces = {}
  @namespaces_written = false

  super
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object

Delegates missing methods to XML::Writer instance



210
211
212
# File 'lib/tilia/xml/writer.rb', line 210

def method_missing(name, *args)
  @writer.send(name, *args)
end

Instance Method Details

#open_memoryvoid

This method returns an undefined value.

Fakes the php function open_memory

Initilizes the LibXML Writer



196
197
198
199
200
# File 'lib/tilia/xml/writer.rb', line 196

def open_memory
  raise 'XML document already created' if @writer

  @writer = ::LibXML::XML::Writer.string
end

#output_memoryString

Fakes the php function output_memory

Returns:

  • (String)


205
206
207
# File 'lib/tilia/xml/writer.rb', line 205

def output_memory
  @writer.result
end

#start_element(name) ⇒ Boolean

Starts an element.

Parameters:

  • name (String)

Returns:

  • (Boolean)


73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/tilia/xml/writer.rb', line 73

def start_element(name)
  if name[0] == '{'
    (namespace, local_name) = Service.parse_clark_notation(name)

    if @namespace_map.key?(namespace)
      tmp_ns = @namespace_map[namespace]
      tmp_ns = nil if tmp_ns.blank?
      result = start_element_ns(tmp_ns, local_name, nil)
    elsif namespace.blank?
      # An empty namespace means it's the global namespace. This is
      # allowed, but it mustn't get a prefix.
      result = start_element(local_name)
      write_attribute('xmlns', '')
    else
      unless @adhoc_namespaces.key?(namespace)
        @adhoc_namespaces[namespace] = 'x' + (@adhoc_namespaces.size + 1).to_s
      end
      result = start_element_ns(@adhoc_namespaces[namespace], local_name, namespace)
    end
  else
    result = @writer.start_element(name)
  end

  unless @namespaces_written
    @namespace_map.each do |ns, prefix|
      write_attribute((prefix.present? ? 'xmlns:' + prefix : 'xmlns'), ns)
    end
    @namespaces_written = true
  end

  result
end

#write(value) ⇒ void

This method returns an undefined value.

Writes a value to the output stream.

The following values are supported:

 1. Scalar values will be written as-is, as text.
 2. Null values will be skipped (resulting in a short xml tag).
 3. If a value is an instance of an Element class, writing will be
    delegated to the object.
 4. If a value is an array, two formats are supported.

Array format 1:
[
  "{namespace}name1" => "..",
  "{namespace}name2" => "..",
]

One element will be created for each key in this array. The values of
this array support any format this method supports (this method is
called recursively).

Array format 2:

[
  [
    "name" => "{namespace}name1"
    "value" => "..",
    "attributes" => [
        "attr" => "attribute value",
    ]
  ],
  [
    "name" => "{namespace}name1"
    "value" => "..",
    "attributes" => [
        "attr" => "attribute value",
    ]
  ]

]

Parameters:

  • value


65
66
67
# File 'lib/tilia/xml/writer.rb', line 65

def write(value)
  Serializer.standard_serializer(self, value)
end

#write_attribute(name, value) ⇒ Boolean

Writes a new attribute.

The name may be specified in clark-notation.

Returns true when successful.

Parameters:

  • name (String)
  • value (String)

Returns:

  • (Boolean)


158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/tilia/xml/writer.rb', line 158

def write_attribute(name, value)
  if name[0] == '{'
    (namespace, local_name) = Service.parse_clark_notation(name)
    if @namespace_map.key?(namespace)
      # It's an attribute with a namespace we know
      write_attribute(
        @namespace_map[namespace] + ':' + local_name,
        value
      )
    else
      # We don't know the namespace, we must add it in-line
      @adhoc_namespaces[namespace] = 'x' + (@adhoc_namespaces.size + 1).to_s unless @adhoc_namespaces.key?(namespace)

      write_attribute_ns(
        @adhoc_namespaces[namespace],
        local_name,
        namespace,
        value
      )
    end
  else
    @writer.write_attribute(name, value)
  end
end

#write_attributes(attributes) ⇒ void

This method returns an undefined value.

Writes a list of attributes.

Attributes are specified as a key->value array.

The key is an attribute name. If the key is a ‘localName’, the current xml namespace is assumed. If it’s a ‘clark notation key’, this namespace will be used instead.

Parameters:

  • attributes (Hash)


143
144
145
146
147
# File 'lib/tilia/xml/writer.rb', line 143

def write_attributes(attributes)
  attributes.each do |name, value|
    write_attribute(name, value)
  end
end

#write_element(name, content = nil) ⇒ Boolean

Write a full element tag and it’s contents.

This method automatically closes the element as well.

The element name may be specified in clark-notation.

Examples:

writer.write_element('{http://www.w3.org/2005/Atom}author',null)
becomes:
<author xmlns="http://www.w3.org/2005" />

writer.write_element('{http://www.w3.org/2005/Atom}author', [
   '{http://www.w3.org/2005/Atom}name' => 'Evert Pot',
])
becomes:
<author xmlns="http://www.w3.org/2005" /><name>Evert Pot</name></author>

Parameters:

  • name (String)
  • content (String) (defaults to: nil)

Returns:

  • (Boolean)


127
128
129
130
131
# File 'lib/tilia/xml/writer.rb', line 127

def write_element(name, content = nil)
  start_element(name)
  write(content) unless content.nil?
  end_element
end