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



8
9
10
# File 'lib/moxml/xml_utils.rb', line 8

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

#normalize_xml_value(value) ⇒ Object



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

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:



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

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



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

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:



28
29
30
31
32
33
# File 'lib/moxml/xml_utils.rb', line 28

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:



12
13
14
15
16
# File 'lib/moxml/xml_utils.rb', line 12

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:



45
46
47
48
49
# File 'lib/moxml/xml_utils.rb', line 45

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:



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

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:



51
52
53
54
55
56
# File 'lib/moxml/xml_utils.rb', line 51

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:



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

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



58
59
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
# File 'lib/moxml/xml_utils.rb', line 58

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