Module: Moxml::XmlEmitter

Defined in:
lib/moxml/xml_emitter.rb

Overview

Single source of XML emission knowledge: character escaping, CDATA end-sequence segmentation, and declaration/DOCTYPE rendering. Adapters keep their tree walks (those are adapter-shaped) but stop re-deriving the wire format:

  • text escapes & < >; attribute values also escape " — apostrophes stay literal (moxml-canonical form)
  • a CDATA section's end sequence is split into adjacent sections
  • the moxml declaration shape is with only the set attributes
  • DOCTYPE renders PUBLIC and SYSTEM external identifiers

Constant Summary collapse

TEXT_ESCAPE_RE =
/[<>&]/
TEXT_ESCAPE_MAP =
{
  "<" => "&lt;", ">" => "&gt;", "&" => "&amp;"
}.freeze
ATTRIBUTE_ESCAPE_RE =
/[<>&"]/
ATTRIBUTE_ESCAPE_MAP =
{
  "<" => "&lt;", ">" => "&gt;", "&" => "&amp;", '"' => "&quot;"
}.freeze
CDATA_END =
"]]>"
CDATA_END_SPLIT =
"]]]]><![CDATA[>"

Class Method Summary collapse

Class Method Details

.cdata(content) ⇒ String

Returns a CDATA section, splitting any embedded end sequence into adjacent sections.

Returns:

  • (String)

    a CDATA section, splitting any embedded end sequence into adjacent sections



47
48
49
# File 'lib/moxml/xml_emitter.rb', line 47

def cdata(content)
  "<![CDATA[#{content.to_s.gsub(CDATA_END, CDATA_END_SPLIT)}]]>"
end

.declaration_xml(version, encoding, standalone) ⇒ String

Returns an XML declaration with only the set attributes.

Returns:

  • (String)

    an XML declaration with only the set attributes



52
53
54
55
56
57
# File 'lib/moxml/xml_emitter.rb', line 52

def declaration_xml(version, encoding, standalone)
  output = %(<?xml version="#{version}")
  output << %( encoding="#{encoding}") if encoding && !encoding.to_s.empty?
  output << %( standalone="#{standalone}") unless standalone.nil?
  output << "?>"
end

.doctype_xml(name, public_id, system_id) ⇒ String

Returns a DOCTYPE with its external identifier.

Returns:

  • (String)

    a DOCTYPE with its external identifier



60
61
62
63
64
65
66
67
68
69
# File 'lib/moxml/xml_emitter.rb', line 60

def doctype_xml(name, public_id, system_id)
  output = "<!DOCTYPE #{name}"
  if public_id && !public_id.to_s.empty?
    output << %( PUBLIC "#{public_id}")
    output << %( "#{system_id}") if system_id
  elsif system_id && !system_id.to_s.empty?
    output << %( SYSTEM "#{system_id}")
  end
  output << ">"
end

.escape_attribute(value) ⇒ String

Returns attribute value with & < > " escaped.

Returns:

  • (String)

    attribute value with & < > " escaped



38
39
40
41
42
43
# File 'lib/moxml/xml_emitter.rb', line 38

def escape_attribute(value)
  str = value.is_a?(String) ? value : value.to_s
  return str unless str.match?(ATTRIBUTE_ESCAPE_RE)

  str.gsub(ATTRIBUTE_ESCAPE_RE, ATTRIBUTE_ESCAPE_MAP)
end

.escape_text(text) ⇒ String

Returns text with & < > escaped.

Returns:

  • (String)

    text with & < > escaped



30
31
32
33
34
35
# File 'lib/moxml/xml_emitter.rb', line 30

def escape_text(text)
  str = text.is_a?(String) ? text : text.to_s
  return str unless str.match?(TEXT_ESCAPE_RE)

  str.gsub(TEXT_ESCAPE_RE, TEXT_ESCAPE_MAP)
end