validate_xml_xsi 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aeccb816b7e38de2b2cc3b29dd0f3035e56f8bf2190f9d1281ae11ec73573efb
4
- data.tar.gz: '0953d2190b837f8b692b468c3e06d77c55cad671a03ed4eaf2e7219e31013cc3'
3
+ metadata.gz: dbe79de11a54ebfff237869fbef6f4ccb9ce8b063dc3305299cb1fcb7856298b
4
+ data.tar.gz: 549031f8aa72adca7434f9294bfef40e2b2ce70b8980b04960cd20ab320dace4
5
5
  SHA512:
6
- metadata.gz: 323fc0b7cd7b322ff35c72dd77ae1b33b5aee6b5bed953ed7b3e965cc7924bb98c36145a2296e279a6c6e208c9aa056e33809f00f3e9272d15b898425bc3e407
7
- data.tar.gz: 8d79a528c2fb9172b2d0d29bcd10f67d241a792fba510b613eed501645d73cb137ed3ba0af0223b5b4cd3510025268184a42e487810428b196d17664778501a1
6
+ metadata.gz: 1336127c5245a94b7a8915f5d87372e17ab52bad43c32d1c07ef165d26db0ca1182baefcc826bd58cd401e213a2f7c04129dfea28d7c950d9fe1e06e2bb6780a
7
+ data.tar.gz: b60f8dcc6904c9b706f338a7afa7438fd98b7029a2a06b9f07010a63e3cddd1f0913bad0bc5ec2d608c3446c137339bb2ae8640251e7b4775ac006b9799e0c75
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## v0.3.0
2
+
3
+ * Change overall structure to make XML_XSI::Schema a normal class (not just a singleton)
4
+ * Allow the Schema to return the xsd document string (so it can be used externally to build a XSD document tree)
5
+
1
6
  ## v0.2.4
2
7
 
3
8
  * Fix some silly syntax errors
data/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # validate_xml_xsi
2
2
 
3
- This gem validates XML against it's xsi using the xsi:schemaLocation elements to define the location of XSD documents.
3
+ This gem validates XML against it's XSD that is created from xsi:schemaLocation elements.
4
4
 
5
- It does this by first parsing the XML and searching for xsi:schemaLocation elements and then creating a schema document that imports the XSD's identified in the XML.
5
+ It does this by first parsing the XML and searching for elements that include xsi:schemaLocation attributes. It then creates an XSD schema document that includes the root namespace and further imports additional namespaces discovered in the XML.
6
6
 
7
- It then validates the document against that schema and outputs any error messages.
7
+ It then validates the document against that constructed schema document and outputs any error messages.
8
8
 
9
- Note: this gem utilizes the 'nokogiri' gem for XML parsing and schema validation.
9
+ Note: this gem utilizes the 'nokogiri' gem (which in turn relies on Gnome's libxml2) for the XML parsing and schema validation.
10
10
 
11
11
  ## Installation
12
12
 
@@ -35,41 +35,53 @@ class XML_XSI
35
35
  end
36
36
 
37
37
  attr_reader :xsd
38
- def initialize(xml_doc)
38
+ def initialize(xml_doc, parent_xml_doc = nil)
39
39
  unless xml_doc.is_a?(Nokogiri::XML::Document)
40
40
  raise DocumentError.new("invalid Nokogiri::XML::Document - #{xml_doc.class.name}")
41
41
  end
42
+ unless parent_xml_doc.nil? || parent_xml_doc.is_a?(Nokogiri::XML::Document)
43
+ raise DocumentError.new("invalid parent Nokogiri::XML::Document - #{parent_xml_doc.class.name}")
44
+ end
42
45
  @document = xml_doc
43
46
  ## Determine default/top/root namespace
44
47
  target_ns_href = nil
45
48
  @document.namespaces.each do |ns_prefix, ns_href|
46
49
  target_ns_href = ns_href if ns_prefix.nil? || ns_prefix.empty? || ns_prefix.eql?('xmlns')
47
50
  end
48
- raise DocumentError.new("Unable to determine default (xmlns) namespace!") if target_ns_href.nil? || target_ns_href.empty?
51
+ if target_ns_href.nil? || target_ns_href.empty?
52
+ raise DocumentError.new("Unable to determine a default (xmlns) namespace!")
53
+ end
54
+
55
+ ## Determine schema locations, optionally inheriting their location declarations from a parent document
56
+ schema_locations = parent_xml_doc.nil? ? {} : self.class.find_schema_locations(parent_xml_doc)
57
+ schema_locations.merge!(self.class.find_schema_locations(@document))
58
+
59
+ ## If we still don't have a file location for the target namespace, attempt to look for
60
+ ## one based on the name of the root node (assuming that where the namespace was declared).
61
+ if !schema_locations.include?(target_ns_href) &&
62
+ @document.root.namespace.href.eql?(target_ns_href)
63
+ root_file_xsd = "#{@document.root.name}.xsd"
64
+ schema_locations[target_ns_href] = root_file_xsd if File.exist?(root_file_xsd)
65
+ end
66
+
67
+ unless schema_locations.include?(target_ns_href)
68
+ ## XXX - Another possibility would be to default to a file named after the node name declaring the xmlns
69
+ raise DocumentError.new("Unable to locate a source/file for the default (xmlns) namespace schema!")
70
+ end
71
+
49
72
  ## Build an all-in-one XSD document that imports all of the separate schema locations
50
73
  @xsd = "<?xml version=\"1.0\"?>\n"
51
74
  @xsd << "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n" \
52
75
  " targetNamespace=\"#{target_ns_href}\"\n" \
53
76
  " version=\"1.0\">\n"
54
- ## Include the default xml namespace
55
- schemata_by_ns = {}
56
- ## Iterate over all the elements and find any xsi:schemaLocation attributes
57
- ## and build a hash of all of the namespaces and locations
58
- @document.search('//*[@xsi:schemaLocation]').each do |elem|
59
- elem['xsi:schemaLocation'].scan(/(\S+)\s+(\S+)/).each do |ns_set|
60
- if ns_loc = schemata_by_ns[ns_set.first]
61
- unless ns_loc.eql?(ns_set.last)
62
- raise DocumentError.new("MISMATCHING namespace: #{ns_set.first} -> #{ns_loc} VS #{ns_set.last}")
63
- end
64
- else
65
- schemata_by_ns[ns_set.first] = ns_set.last
66
- end
67
- end
68
- end
69
- schemata_by_ns.each do |ns_href, ns_file|
70
- @xsd << (ns_href.eql?(target_ns_href) ?
71
- " <xsd:include schemaLocation=\"#{ns_file}\"/>\n" :
72
- " <xsd:import namespace=\"#{ns_href}\" schemaLocation=\"#{ns_file}\"/>\n")
77
+
78
+ ## Minimally we need the target namespace location or we have nothing to include
79
+ target_ns_file = schema_locations.delete(target_ns_href)
80
+ @xsd << " <xsd:include schemaLocation=\"#{target_ns_file}\"/>\n" unless target_ns_file.nil?
81
+
82
+ ## Now add imports for the other defined schemaLocations
83
+ schema_locations.each do |ns_href, ns_file|
84
+ @xsd << " <xsd:import namespace=\"#{ns_href}\" schemaLocation=\"#{ns_file}\"/>\n"
73
85
  end
74
86
  @xsd << "</xsd:schema>\n"
75
87
 
@@ -89,5 +101,32 @@ class XML_XSI
89
101
  end
90
102
  errors
91
103
  end
104
+
105
+ def self.find_schema_locations(xml_doc)
106
+ ## Include the default xml namespace
107
+ schema_locations = {}
108
+
109
+ ## Determine if the document has reference to the namespace "http://www.w3.org/2001/XMLSchema-instance"
110
+ ## which is used for defining schemaLocations
111
+ xsi_prefix = xml_doc.namespaces.invert['http://www.w3.org/2001/XMLSchema-instance']&.delete_prefix('xmlns:')
112
+
113
+ ## Iterate over all the elements and find any xsi:schemaLocation attributes
114
+ ## and build a hash of all of the namespaces and locations
115
+ unless xsi_prefix.nil?
116
+ xsi_loc = "#{xsi_prefix}:schemaLocation"
117
+ xml_doc.search("//*[@#{xsi_loc}]").each do |elem|
118
+ elem[xsi_loc].scan(/(\S+)\s+(\S+)/).each do |ns_set|
119
+ if ns_loc = schema_locations[ns_set.first]
120
+ unless ns_loc.eql?(ns_set.last)
121
+ raise DocumentError.new("MISMATCHING namespace: #{ns_set.first} -> #{ns_loc} VS #{ns_set.last}")
122
+ end
123
+ else
124
+ schema_locations[ns_set.first] = ns_set.last
125
+ end
126
+ end
127
+ end
128
+ end
129
+ schema_locations
130
+ end
92
131
  end
93
132
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "validate_xml_xsi"
3
- spec.version = "0.3.0"
3
+ spec.version = "0.4.0"
4
4
  spec.authors = ["David Hansen"]
5
5
  spec.email = ["david@hansen4.net"]
6
6
 
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: validate_xml_xsi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Hansen
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2022-03-25 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: bundler
@@ -52,7 +51,6 @@ dependencies:
52
51
  - - ">="
53
52
  - !ruby/object:Gem::Version
54
53
  version: 1.13.2
55
- description:
56
54
  email:
57
55
  - david@hansen4.net
58
56
  executables:
@@ -76,7 +74,6 @@ metadata:
76
74
  homepage_uri: https://github.com/d-hansen/validate_xml_xsi
77
75
  source_code_uri: https://github.com/d-hansen/validate_xml_xsi
78
76
  changelog_uri: https://github.com/d-hansen/validate_xml_xsi/blob/master/CHANGELOG.md
79
- post_install_message:
80
77
  rdoc_options: []
81
78
  require_paths:
82
79
  - lib
@@ -91,8 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
88
  - !ruby/object:Gem::Version
92
89
  version: '0'
93
90
  requirements: []
94
- rubygems_version: 3.3.8
95
- signing_key:
91
+ rubygems_version: 4.0.2
96
92
  specification_version: 4
97
93
  summary: Validate XML against it's embedded XSI elements that define the XSD's.
98
94
  test_files: []