Module: Moxml::XmlUtils

Included in:
Adapter::Base, Node
Defined in:
lib/moxml/xml_utils.rb,
lib/moxml/xml_utils/encoder.rb

Defined Under Namespace

Classes: Encoder

Instance Method Summary collapse

Instance Method Details

#encode_entities(text, mode = nil) ⇒ Object



10
11
12
# File 'lib/moxml/xml_utils.rb', line 10

def encode_entities(text, mode = nil)
  Encoder.new(text, mode).call
end

#normalize_xml_value(value) ⇒ Object



97
98
99
100
101
102
103
104
# File 'lib/moxml/xml_utils.rb', line 97

def normalize_xml_value(value)
  case value
  when nil then ""
  when true then "true"
  when false then "false"
  else value.to_s
  end
end

#validate_comment_content(text) ⇒ Object

Raises:



37
38
39
40
41
42
43
44
45
# File 'lib/moxml/xml_utils.rb', line 37

def validate_comment_content(text)
  if text.start_with?("-") || text.end_with?("-")
    raise ValidationError, "XML comment cannot start or end with a hyphen"
  end

  return unless text.include?("--")

  raise ValidationError, "XML comment cannot contain double hyphens (--)"
end

#validate_declaration_encoding(encoding) ⇒ Object



20
21
22
23
24
25
26
27
28
# File 'lib/moxml/xml_utils.rb', line 20

def validate_declaration_encoding(encoding)
  return if encoding.nil?

  begin
    Encoding.find(encoding)
  rescue ArgumentError
    raise ValidationError, "Invalid encoding: #{encoding}"
  end
end

#validate_declaration_standalone(standalone) ⇒ Object

Raises:



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

def validate_declaration_standalone(standalone)
  return if standalone.nil?
  return if ::Moxml::Declaration::ALLOWED_STANDALONE.include?(standalone)

  raise ValidationError, "Invalid standalone value: #{standalone}"
end

#validate_declaration_version(version) ⇒ Object

Raises:



14
15
16
17
18
# File 'lib/moxml/xml_utils.rb', line 14

def validate_declaration_version(version)
  return if ::Moxml::Declaration::ALLOWED_VERSIONS.include?(version)

  raise ValidationError, "Invalid XML version: #{version}"
end

#validate_element_name(name) ⇒ Object

Raises:



47
48
49
50
51
# File 'lib/moxml/xml_utils.rb', line 47

def validate_element_name(name)
  return if name.is_a?(String) && name.match?(/^[a-zA-Z_][\w\-.:]*$/)

  raise ValidationError, "Invalid XML element name: #{name}"
end

#validate_entity_reference_name(name) ⇒ Object

Raises:



106
107
108
109
110
111
112
# File 'lib/moxml/xml_utils.rb', line 106

def validate_entity_reference_name(name)
  # Entity names follow the same pattern as element names
  # They must start with a letter or underscore, followed by letters, digits, hyphens, underscores, periods, or colons
  return if name.is_a?(String) && name.match?(/^[a-zA-Z_][\w\-.:]*$/)

  raise ValidationError, "Invalid entity reference name: #{name}"
end

#validate_pi_target(target) ⇒ Object

Raises:



53
54
55
56
57
58
# File 'lib/moxml/xml_utils.rb', line 53

def validate_pi_target(target)
  return if target.is_a?(String) && target.match?(/^[a-zA-Z_][\w\-.]*$/)

  raise ValidationError,
        "Invalid XML processing instruction target: #{target}"
end

#validate_prefix(prefix) ⇒ Object

Raises:



91
92
93
94
95
# File 'lib/moxml/xml_utils.rb', line 91

def validate_prefix(prefix)
  return if prefix.match?(/\A[a-zA-Z_][\w.-]*\z/)

  raise ValidationError, "Invalid namespace prefix: #{prefix}"
end

#validate_uri(uri, mode: :strict) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/moxml/xml_utils.rb', line 60

def validate_uri(uri, mode: :strict)
  # Empty strings are allowed for default namespace undeclaration (xmlns="").
  return if uri.empty?

  # In lenient mode, accept any string as a namespace URI.
  # Only reject strings containing XML-invalid characters (control characters).
  if mode == :lenient
    if uri.match?(/[\x00-\x08\x0B\x0C\x0E-\x1F]/)
      raise ValidationError, "Invalid URI: #{uri}"
    end

    return
  end

  # Namespace names must be valid URI-references per RFC 3986
  # (W3C Namespaces in XML, https://www.w3.org/TR/xml-names/).
  # Use split instead of parse to avoid scheme-specific validation
  # that rejects valid opaque URIs like "mailto:bar".
  if defined?(URI::RFC3986_PARSER)
    URI::RFC3986_PARSER.split(uri)
  elsif uri.match?(/\A[a-zA-Z][a-zA-Z0-9+\-.]*:[^\x00-\x20]*\z/)
    # Minimal URI validation for Opal (no RFC3986_PARSER available)
  else
    # Accept relative references and bare paths
    return unless uri.match?(/[\x00-\x08\x0B\x0C\x0E-\x1F]/)
    raise ValidationError, "Invalid URI: #{uri}"
  end
rescue URI::InvalidURIError
  raise ValidationError, "Invalid URI: #{uri}"
end