Module: Cetustek::Xml
- Defined in:
- lib/cetustek/xml.rb
Overview
Every request document in the spec is the same shape: a UTF-8 declaration
and a single
Constant Summary collapse
- XSD_VERSION =
'2.8'
Class Method Summary collapse
-
.append(element, name, value, skip_nil: false) ⇒ Object
Fields whose 備註 says "若未填,預設 X" are left out entirely when nil, so the platform applies its own default instead of parsing an empty value.
- .document(root_name) {|root| ... } ⇒ Object
-
.parse_fields(element, fields) ⇒ Object
Shared response-parsing side: every Query* class turns a response element into a Hash of snake_case keys, so this lives here once instead of once per query class.
-
.parse_response(body, nil_values: []) ⇒ Object
Shared guard every Query* class needs before it can parse a response body: nil for an empty answer or one of the documented sentinel strings (e.g. "nodata"); ResultError for a bare result code; otherwise the parsed root element, ready for parse_fields.
- .snake_case(name) ⇒ Object
-
.tag(name, value) ⇒ Object
Values are HTML-escaped so that special characters (&, <, >, ", ') in any dynamic field cannot break the XML or be used for injection.
- .text_of(element, name) ⇒ Object
Class Method Details
.append(element, name, value, skip_nil: false) ⇒ Object
Fields whose 備註 says "若未填,預設 X" are left out entirely when nil, so the platform applies its own default instead of parsing an empty value.
37 38 39 40 41 |
# File 'lib/cetustek/xml.rb', line 37 def append(element, name, value, skip_nil: false) return if skip_nil && value.nil? element << tag(name, value) end |
.document(root_name) {|root| ... } ⇒ Object
14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/cetustek/xml.rb', line 14 def document(root_name) doc = Ox::Document.new instruct = Ox::Instruct.new(:xml) instruct[:version] = '1.0' instruct[:encoding] = 'UTF-8' doc << instruct root = Ox::Element.new(root_name) root[:XSDVersion] = XSD_VERSION doc << root yield root Ox.dump(doc).force_encoding('UTF-8') end |
.parse_fields(element, fields) ⇒ Object
Shared response-parsing side: every Query* class turns a response element into a Hash of snake_case keys, so this lives here once instead of once per query class.
60 61 62 |
# File 'lib/cetustek/xml.rb', line 60 def parse_fields(element, fields) fields.to_h { |field| [snake_case(field), text_of(element, field)] } end |
.parse_response(body, nil_values: []) ⇒ Object
Shared guard every Query* class needs before it can parse a response body: nil for an empty answer or one of the documented sentinel strings (e.g. "nodata"); ResultError for a bare result code; otherwise the parsed root element, ready for parse_fields.
47 48 49 50 51 52 53 54 55 |
# File 'lib/cetustek/xml.rb', line 47 def parse_response(body, nil_values: []) text = body.to_s.strip return nil if text.empty? || nil_values.include?(text) ResultCode.raise!(text, ResultCode::COMMON) unless text.start_with?('<') root = Ox.parse(text) root.is_a?(Ox::Document) ? root.root : root end |
.snake_case(name) ⇒ Object
68 69 70 |
# File 'lib/cetustek/xml.rb', line 68 def snake_case(name) name.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase.to_sym end |
.tag(name, value) ⇒ Object
Values are HTML-escaped so that special characters (&, <, >, ", ') in any dynamic field cannot break the XML or be used for injection.
31 32 33 |
# File 'lib/cetustek/xml.rb', line 31 def tag(name, value) Ox::Raw.new("<#{name}>#{CGI.escapeHTML(value.to_s)}</#{name}>") end |
.text_of(element, name) ⇒ Object
64 65 66 |
# File 'lib/cetustek/xml.rb', line 64 def text_of(element, name) element&.locate(name)&.first&.text end |