Module: Lutaml::Xml::DeclarationHandler
- Included in:
- Adapter::BaseAdapter
- Defined in:
- lib/lutaml/xml/declaration_handler.rb
Overview
DeclarationHandler provides XML declaration extraction from input XML.
Extraction methods detect and parse XML declarations from input strings. Generation is handled by moxml’s document model — no manual string assembly.
Class Method Summary collapse
-
.extract_attribute(content, attr_name) ⇒ String?
Extract an attribute value from declaration content Uses simple string parsing to avoid regex ReDoS.
-
.extract_xml_declaration(xml) ⇒ Hash
Extract XML declaration information from input string.
Instance Method Summary collapse
-
#should_include_declaration?(options, xml_declaration = nil) ⇒ Boolean
Determine if XML declaration should be included in output.
Class Method Details
.extract_attribute(content, attr_name) ⇒ String?
Extract an attribute value from declaration content Uses simple string parsing to avoid regex ReDoS
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/lutaml/xml/declaration_handler.rb', line 57 def self.extract_attribute(content, attr_name) # Find attribute name followed by = name_start = content.index("#{attr_name}=") return nil unless name_start # Get the position after attr= pos = name_start + attr_name.length + 1 # Skip any whitespace pos += 1 while pos < content.length && content[pos] == " " return nil if pos >= content.length # Check quote character quote = content[pos] return nil unless ['"', "'"].include?(quote) # Find closing quote end_quote = content.index(quote, pos + 1) return nil unless end_quote # Extract value between quotes content[(pos + 1)...end_quote] end |
.extract_xml_declaration(xml) ⇒ Hash
Extract XML declaration information from input string
Detects if input had an XML declaration and extracts version/encoding/standalone. This is used for round-trip preservation of declarations.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/lutaml/xml/declaration_handler.rb', line 15 def self.extract_xml_declaration(xml) # Use string operations instead of regex to avoid ReDoS vulnerability # This approach is O(n) with no backtracking # Strip leading whitespace trimmed = xml.lstrip # Fast prefix check - no regex needed return { had_declaration: false } unless trimmed.start_with?("<?xml") # Find the end of the declaration (?>) # Limit search to first 100 chars to avoid scanning entire document search_region = trimmed[0, 100] end_pos = search_region.index("?>", 5) return { had_declaration: false } unless end_pos # Extract content between <?xml and ?> decl_content = trimmed[5...end_pos] # Extract version (defaults to "1.0") version = extract_attribute(decl_content, "version") || "1.0" # Extract encoding (may be absent) encoding = extract_attribute(decl_content, "encoding") # Extract standalone (may be absent) standalone = extract_attribute(decl_content, "standalone") { version: version, encoding: encoding, standalone: standalone, had_declaration: true, } end |
Instance Method Details
#should_include_declaration?(options, xml_declaration = nil) ⇒ Boolean
Determine if XML declaration should be included in output
Supports multiple modes:
-
false: omit declaration
-
true: force include with defaults
-
:preserve: include if input had one
-
String: custom version string
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/lutaml/xml/declaration_handler.rb', line 93 def should_include_declaration?(, xml_declaration = nil) xml_declaration ||= @xml_declaration if .key?(:declaration) case [:declaration] when false false when true true when :preserve xml_declaration&.dig(:had_declaration) || false when String true else xml_declaration&.dig(:had_declaration) || false end else xml_declaration&.dig(:had_declaration) || false end end |