ruby3mf 0.1.17 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 152e1cd32d11dadcadb62904f2942100278d059c
4
- data.tar.gz: 3359551e080d311dbdbe6a8607f0336cbfedf298
3
+ metadata.gz: c96a243d6561a8d9bf5a047012d87275035191ae
4
+ data.tar.gz: 7e913c8167d75dff3aad79a74fda2270b4c2811a
5
5
  SHA512:
6
- metadata.gz: 670d9a203081c4da7d93cdb8dc81e8db53352a5bd6635511f028a29e073bc8ffb5325365f7539d9718227bd6646fb2d5b00b5c6b1cc3161dfe77528cea6ae242
7
- data.tar.gz: 48bf7933386810d11e503953607545b3db168949c97123836fadec03fb10392530732b11b02b40d02c761eccac96fca9e62bb5716c2d289da3c32c46a5026bdb
6
+ metadata.gz: 537228530d6b5baf851932a7c920b99b85ad25a202dfb6d5f20887b7cf9cb195588425031079bf483533d2f9bb06e856fe5f34f17fa18d8574baed3162fac2c5
7
+ data.tar.gz: d416b8615337f1a199e6f8e0f968a754e07204a377d0b9cce7de63822bef42c84eb08feadd179552ae36f84b7a7bac0293fdae121b79053d354573f9efaa20bd
@@ -0,0 +1,188 @@
1
+ <xs:schema xmlns="http://schemas.microsoft.com/3dmanufacturing/core/2015/02" xmlns:xs="http://www.w3.org/2001/XMLSchema"
2
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
3
+ targetNamespace="http://schemas.microsoft.com/3dmanufacturing/core/2015/02" elementFormDefault="unqualified"
4
+ attributeFormDefault="unqualified" blockDefault="#all">
5
+ <xs:import namespace="http://www.w3.org/XML/1998/namespace"
6
+ schemaLocation="http://www.w3.org/2001/xml.xsd"/>
7
+ <xs:annotation>
8
+ <xs:documentation><![CDATA[
9
+ Schema notes:
10
+ Items within this schema follow a simple naming convention of appending a prefix indicating the type of element for references:
11
+ Unprefixed: Element names
12
+ CT_: Complex types
13
+ ST_: Simple types
14
+ ]]></xs:documentation>
15
+ </xs:annotation>
16
+ <!-- Complex Types -->
17
+ <xs:complexType name="CT_Model">
18
+ <xs:sequence>
19
+ <xs:element ref="metadata" minOccurs="0" maxOccurs="30000"/>
20
+ <xs:element ref="resources"/>
21
+ <xs:element ref="build"/>
22
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="30000"/>
23
+ </xs:sequence>
24
+ <xs:attribute name="unit" type="ST_Unit" default="millimeter"/>
25
+ <xs:attribute ref="xml:lang"/>
26
+ <xs:attribute name="requiredextensions" type="xs:string"/>
27
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
28
+ </xs:complexType>
29
+ <xs:complexType name="CT_Resources">
30
+ <xs:sequence>
31
+ <xs:element ref="basematerials" minOccurs="0" maxOccurs="30000"/>
32
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="30000"/>
33
+ <xs:element ref="object" minOccurs="0" maxOccurs="30000"/>
34
+ </xs:sequence>
35
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
36
+ </xs:complexType>
37
+ <xs:complexType name="CT_Build">
38
+ <xs:sequence>
39
+ <xs:element ref="item" minOccurs="0" maxOccurs="30000"/>
40
+ </xs:sequence>
41
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
42
+ </xs:complexType>
43
+ <xs:complexType name="CT_BaseMaterials">
44
+ <xs:sequence>
45
+ <xs:element ref="base" maxOccurs="30000"/>
46
+ </xs:sequence>
47
+ <xs:attribute name="id" type="ST_ResourceID" use="required"/>
48
+ </xs:complexType>
49
+ <xs:complexType name="CT_Base">
50
+ <xs:attribute name="name" type="xs:string" use="required"/>
51
+ <xs:attribute name="displaycolor" type="ST_ColorValue" use="required"/>
52
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
53
+ </xs:complexType>
54
+ <xs:complexType name="CT_Object">
55
+ <xs:choice>
56
+ <xs:element ref="mesh"/>
57
+ <xs:element ref="components"/>
58
+ </xs:choice>
59
+ <xs:attribute name="id" type="ST_ResourceID" use="required"/>
60
+ <xs:attribute name="type" type="ST_ObjectType" default="model"/>
61
+ <xs:attribute name="matid" type="ST_ResourceID"/>
62
+ <xs:attribute name="matindex" type="ST_ResourceIndex"/>
63
+ <xs:attribute name="partnumber" type="xs:string"/>
64
+ <xs:attribute name="name" type="xs:string"/>
65
+ <xs:attribute name="pid" type="ST_ResourceID"/>
66
+ <xs:attribute name="pindex" type="ST_ResourceIndex"/>
67
+ <xs:attribute name="thumbnail" type="ST_UriReference" />
68
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
69
+ </xs:complexType>
70
+ <xs:complexType name="CT_Mesh">
71
+ <xs:sequence>
72
+ <xs:element ref="vertices"/>
73
+ <xs:element ref="triangles"/>
74
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="30000"/>
75
+ </xs:sequence>
76
+ </xs:complexType>
77
+ <xs:complexType name="CT_Vertices">
78
+ <xs:sequence>
79
+ <xs:element ref="vertex" minOccurs="3" maxOccurs="30000"/>
80
+ </xs:sequence>
81
+ </xs:complexType>
82
+ <xs:complexType name="CT_Vertex">
83
+ <xs:attribute name="x" type="ST_Number" use="required"/>
84
+ <xs:attribute name="y" type="ST_Number" use="required"/>
85
+ <xs:attribute name="z" type="ST_Number" use="required"/>
86
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
87
+ </xs:complexType>
88
+ <xs:complexType name="CT_Triangles">
89
+ <xs:sequence>
90
+ <xs:element ref="triangle" minOccurs="1" maxOccurs="30000"/>
91
+ </xs:sequence>
92
+ </xs:complexType>
93
+ <xs:complexType name="CT_Triangle">
94
+ <xs:attribute name="v1" type="ST_ResourceIndex" use="required"/>
95
+ <xs:attribute name="v2" type="ST_ResourceIndex" use="required"/>
96
+ <xs:attribute name="v3" type="ST_ResourceIndex" use="required"/>
97
+ <xs:attribute name="p1" type="ST_ResourceIndex"/>
98
+ <xs:attribute name="p2" type="ST_ResourceIndex"/>
99
+ <xs:attribute name="p3" type="ST_ResourceIndex"/>
100
+ <xs:attribute name="pid" type="ST_ResourceID"/>
101
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
102
+ </xs:complexType>
103
+ <xs:complexType name="CT_Components">
104
+ <xs:sequence>
105
+ <xs:element ref="component" maxOccurs="30000"/>
106
+ </xs:sequence>
107
+ </xs:complexType>
108
+ <xs:complexType name="CT_Component">
109
+ <xs:attribute name="objectid" type="ST_ResourceID" use="required"/>
110
+ <xs:attribute name="transform" type="ST_Matrix3D"/>
111
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
112
+ </xs:complexType>
113
+ <xs:complexType name="CT_Metadata" mixed="true">
114
+ <xs:attribute name="name" type="xs:QName" use="required"/>
115
+ </xs:complexType>
116
+ <xs:complexType name="CT_Item">
117
+ <xs:attribute name="objectid" type="ST_ResourceID" use="required"/>
118
+ <xs:attribute name="transform" type="ST_Matrix3D"/>
119
+ <xs:attribute name="itemref" type="xs:ID"/>
120
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
121
+ </xs:complexType>
122
+ <!-- Simple Types -->
123
+ <xs:simpleType name="ST_Unit">
124
+ <xs:restriction base="xs:string">
125
+ <xs:enumeration value="micron"/>
126
+ <xs:enumeration value="millimeter"/>
127
+ <xs:enumeration value="centimeter"/>
128
+ <xs:enumeration value="inch"/>
129
+ <xs:enumeration value="foot"/>
130
+ <xs:enumeration value="meter"/>
131
+ </xs:restriction>
132
+ </xs:simpleType>
133
+ <xs:simpleType name="ST_ColorValue">
134
+ <xs:restriction base="xs:string">
135
+ <xs:pattern value="#[0-9|A-F|a-f][0-9|A-F|a-f][0-9|A-F|a-f][0-9|A-F|a-f][0-9|A-F|a-f][0-9|A-F|a-f]([0-9|A-F|a-f][0-9|A-F|a-f])?"/>
136
+ </xs:restriction>
137
+ </xs:simpleType>
138
+ <xs:simpleType name="ST_UriReference">
139
+ <xs:restriction base="xs:anyURI">
140
+ <xs:pattern value="/.*"/>
141
+ </xs:restriction>
142
+ </xs:simpleType>
143
+ <xs:simpleType name="ST_Matrix3D">
144
+ <xs:restriction base="xs:string">
145
+ <xs:pattern value="((\-|\+)?(([0-9]+(\.[0-9]+)?)|(\.[0-9]+))((e|E)(\-|\+)?[0-9]+)?) ((\-|\+)?(([0-9]+(\.[0-9]+)?)|(\.[0-9]+))((e|E)(\-|\+)?[0-9]+)?) ((\-|\+)?(([0-9]+(\.[0-9]+)?)|(\.[0-9]+))((e|E)(\-|\+)?[0-9]+)?) ((\-|\+)?(([0-9]+(\.[0-9]+)?)|(\.[0-9]+))((e|E)(\-|\+)?[0-9]+)?) ((\-|\+)?(([0-9]+(\.[0-9]+)?)|(\.[0-9]+))((e|E)(\-|\+)?[0-9]+)?) ((\-|\+)?(([0-9]+(\.[0-9]+)?)|(\.[0-9]+))((e|E)(\-|\+)?[0-9]+)?) ((\-|\+)?(([0-9]+(\.[0-9]+)?)|(\.[0-9]+))((e|E)(\-|\+)?[0-9]+)?) ((\-|\+)?(([0-9]+(\.[0-9]+)?)|(\.[0-9]+))((e|E)(\-|\+)?[0-9]+)?) ((\-|\+)?(([0-9]+(\.[0-9]+)?)|(\.[0-9]+))((e|E)(\-|\+)?[0-9]+)?) ((\-|\+)?(([0-9]+(\.[0-9]+)?)|(\.[0-9]+))((e|E)(\-|\+)?[0-9]+)?) ((\-|\+)?(([0-9]+(\.[0-9]+)?)|(\.[0-9]+))((e|E)(\-|\+)?[0-9]+)?) ((\-|\+)?(([0-9]+(\.[0-9]+)?)|(\.[0-9]+))((e|E)(\-|\+)?[0-9]+)?)"/>
146
+ </xs:restriction>
147
+ </xs:simpleType>
148
+ <xs:simpleType name="ST_Number">
149
+ <xs:restriction base="xs:double">
150
+ <xs:whiteSpace value="collapse"/>
151
+ <xs:pattern value="((\-|\+)?(([0-9]+(\.[0-9]+)?)|(\.[0-9]+))((e|E)(\-|\+)?[0-9]+)?)"/>
152
+ </xs:restriction>
153
+ </xs:simpleType>
154
+ <xs:simpleType name="ST_ResourceID">
155
+ <xs:restriction base="xs:positiveInteger">
156
+ <xs:maxExclusive value="2147483648"/>
157
+ </xs:restriction>
158
+ </xs:simpleType>
159
+ <xs:simpleType name="ST_ResourceIndex">
160
+ <xs:restriction base="xs:nonNegativeInteger">
161
+ <xs:maxExclusive value="2147483648"/>
162
+ </xs:restriction>
163
+ </xs:simpleType>
164
+ <xs:simpleType name="ST_ObjectType">
165
+ <xs:restriction base="xs:string">
166
+ <xs:enumeration value="model"/>
167
+ <xs:enumeration value="solidsupport"/>
168
+ <xs:enumeration value="support"/>
169
+ <xs:enumeration value="other"/>
170
+ </xs:restriction>
171
+ </xs:simpleType>
172
+ <!-- Elements -->
173
+ <xs:element name="model" type="CT_Model"/>
174
+ <xs:element name="resources" type="CT_Resources"/>
175
+ <xs:element name="build" type="CT_Build"/>
176
+ <xs:element name="basematerials" type="CT_BaseMaterials"/>
177
+ <xs:element name="base" type="CT_Base"/>
178
+ <xs:element name="object" type="CT_Object"/>
179
+ <xs:element name="mesh" type="CT_Mesh"/>
180
+ <xs:element name="vertices" type="CT_Vertices"/>
181
+ <xs:element name="vertex" type="CT_Vertex"/>
182
+ <xs:element name="triangles" type="CT_Triangles"/>
183
+ <xs:element name="triangle" type="CT_Triangle"/>
184
+ <xs:element name="components" type="CT_Components"/>
185
+ <xs:element name="component" type="CT_Component"/>
186
+ <xs:element name="metadata" type="CT_Metadata"/>
187
+ <xs:element name="item" type="CT_Item"/>
188
+ </xs:schema>
@@ -30,7 +30,7 @@ class Document
30
30
  self.thumbnails=[]
31
31
  self.textures=[]
32
32
  self.objects={}
33
- self.relationships=[]
33
+ self.relationships={}
34
34
  self.types=[]
35
35
  self.parts=[]
36
36
  @zip_filename = zip_filename
@@ -91,6 +91,7 @@ class Document
91
91
  begin
92
92
  u = URI part.name
93
93
  rescue ArgumentError, URI::InvalidURIError
94
+ l.fatal_error "This NEVER Happens! mdw 12Jan2017"
94
95
  l.error :err_uri_bad
95
96
  next
96
97
  end
@@ -104,7 +105,6 @@ class Document
104
105
  end
105
106
 
106
107
  l.context 'content types' do |l|
107
- # 1. Get Content Types
108
108
  content_type_match = zip_file.glob('\[Content_Types\].xml').first
109
109
  if content_type_match
110
110
  m.types = ContentTypes.parse(content_type_match)
@@ -114,58 +114,54 @@ class Document
114
114
  end
115
115
 
116
116
  l.context 'relationships' do |l|
117
- # 2. Get Relationships
118
- # rel_folders = zip_file.glob('**/_rels')
119
- # l.fatal_error "Missing any _rels folder", page: 4 unless rel_folders.size>0
120
-
121
- # 2.1 Validate that the top level _rels/.rel file exists
122
117
  rel_file = zip_file.glob('_rels/.rels').first
123
118
  l.fatal_error 'Missing required file _rels/.rels', page: 4 unless rel_file
124
119
 
125
120
  zip_file.glob('**/*.rels').each do |rel|
126
- m.relationships += Relationships.parse(rel)
121
+ m.relationships[rel.name] = Relationships.parse(rel)
127
122
  end
128
123
  end
129
124
 
130
125
  l.context "print tickets" do |l|
131
- print_ticket_types = m.relationships.select { |rel| rel[:type] == PRINT_TICKET_TYPE }
126
+ print_ticket_types = m.relationships.flat_map { |k, v| v }.select { |rel| rel[:type] == PRINT_TICKET_TYPE }
132
127
  l.error :multiple_print_tickets if print_ticket_types.size > 1
133
128
  end
134
129
 
135
130
  l.context "relationship elements" do |l|
136
- # 3. Validate all relationships
137
- m.relationships.each do |rel|
138
- l.context rel[:target] do |l|
139
-
140
- begin
141
- u = URI rel[:target]
142
- rescue URI::InvalidURIError
143
- l.error :err_uri_bad
144
- next
145
- end
131
+ m.relationships.each do |file_name, rels|
132
+ rels.each do |rel|
133
+ l.context rel[:target] do |l|
134
+
135
+ begin
136
+ u = URI rel[:target]
137
+ rescue URI::InvalidURIError
138
+ l.error :err_uri_bad
139
+ next
140
+ end
146
141
 
147
- l.error :err_uri_relative_path unless u.to_s.start_with? '/'
142
+ l.error :err_uri_relative_path unless u.to_s.start_with? '/'
148
143
 
149
- target = rel[:target].gsub(/^\//, "")
150
- l.error :err_uri_empty_segment if target.end_with? '/' or target.include? '//'
151
- l.error :err_uri_relative_path if target.include? '/../'
152
- relationship_file = zip_file.glob(target).first
144
+ target = rel[:target].gsub(/^\//, "")
145
+ l.error :err_uri_empty_segment if target.end_with? '/' or target.include? '//'
146
+ l.error :err_uri_relative_path if target.include? '/../'
147
+ relationship_file = zip_file.glob(target).first
153
148
 
154
- if relationship_file
155
- relationship_type = RELATIONSHIP_TYPES[rel[:type]]
156
- if relationship_type.nil?
157
- l.error :invalid_relationship_type, type: rel[:type]
158
- else
159
- unless relationship_type[:klass].nil?
160
- m.send(relationship_type[:collection]) << {
149
+ if relationship_file
150
+ relationship_type = RELATIONSHIP_TYPES[rel[:type]]
151
+ if relationship_type.nil?
152
+ l.error :invalid_relationship_type, type: rel[:type]
153
+ else
154
+ unless relationship_type[:klass].nil?
155
+ m.send(relationship_type[:collection]) << {
161
156
  rel_id: rel[:id],
162
157
  target: rel[:target],
163
158
  object: Object.const_get(relationship_type[:klass]).parse(m, relationship_file)
164
- }
159
+ }
160
+ end
165
161
  end
162
+ else
163
+ l.error "Relationship Target file #{rel[:target]} not found", page: 11
166
164
  end
167
- else
168
- l.error "Relationship Target file #{rel[:target]} not found", page: 11
169
165
  end
170
166
  end
171
167
  end
@@ -14,7 +14,7 @@ err_uri_relative_path:
14
14
  msg: 'Part names must not include relative paths'
15
15
  page: 13
16
16
  model_resource_not_in_rels:
17
- msg: "Missing required resource: %{mr} Resource referenced in model, but not in .rels relationship file"
17
+ msg: "Missing required resource: %{mr}. Resource referenced in model, but not in .rels relationship file"
18
18
  page: 10
19
19
  resource_3dmodel_orientation:
20
20
  msg: "Bad triangle orientation"
@@ -132,4 +132,7 @@ has_commas_for_floats:
132
132
  page: 15
133
133
  invalid_language_locale:
134
134
  msg: "locale should be en-US"
135
- page: 15
135
+ page: 15
136
+ invalid_xml_core:
137
+ msg: "XML file doesn't pass validation with the XSD file"
138
+ page: 41
@@ -2,19 +2,21 @@ require_relative 'mesh_analyzer'
2
2
 
3
3
  class Model3mf
4
4
 
5
- VALID_UNITS = [ 'micron', 'millimeter', 'centimeter', 'meter', 'inch', 'foot' ].freeze
5
+ VALID_UNITS = ['micron', 'millimeter', 'centimeter', 'meter', 'inch', 'foot'].freeze
6
6
  VALID_EXTENSIONS = {
7
7
  'http://schemas.microsoft.com/3dmanufacturing/slice/2015/07' => {},
8
8
  'http://schemas.microsoft.com/3dmanufacturing/material/2015/02' => {},
9
9
  'http://schemas.microsoft.com/3dmanufacturing/production/2015/06' => {},
10
10
  }.freeze
11
11
 
12
+ SCHEMA = '3MFcoreSpec_1.1.xsd'
13
+
12
14
  def self.parse(document, zip_entry)
13
15
  model_doc = nil
14
16
 
15
17
  Log3mf.context "parsing model" do |l|
16
18
  begin
17
- model_doc = XmlVal.validate_parse(zip_entry)
19
+ model_doc = XmlVal.validate_parse(zip_entry, SCHEMA)
18
20
  rescue Nokogiri::XML::SyntaxError => e
19
21
  l.fatal_error "Model file invalid XML. Exception #{e}"
20
22
  end
@@ -40,9 +42,15 @@ class Model3mf
40
42
  l.context "verifying 3D payload required resources" do |l|
41
43
  # results = model_doc.css("model resources m:texture2d")
42
44
  required_resources = model_doc.css("//model//resources//*[path]").collect { |n| n["path"] }
45
+ required_resources += model_doc.css("//model//resources//object[thumbnail]").collect { |n| n["thumbnail"] }
43
46
 
44
47
  # for each, ensure that they exist in m.relationships
45
- relationship_resources = document.relationships.map { |relationship| relationship[:target] }
48
+ relationship_resources = []
49
+ rel_file = "#{Pathname(zip_entry.name).dirname.to_s}/_rels/#{File.basename(zip_entry.name)}.rels"
50
+ relationships = document.relationships[rel_file]
51
+ unless (relationships.nil?)
52
+ relationship_resources = relationships.map { |relationship| relationship[:target] }
53
+ end
46
54
 
47
55
  missing_resources = (required_resources - relationship_resources)
48
56
  if missing_resources.empty?
@@ -79,16 +87,6 @@ class Model3mf
79
87
  end
80
88
  end
81
89
 
82
- l.context "verifying model structure" do |l|
83
- root = model_doc.root
84
- l.error :root_3dmodel_element_not_model if root.name != "model"
85
-
86
- l.error(:invalid_model_unit, unit: root.attr('unit')) unless VALID_UNITS.include?(root.attr('unit'))
87
-
88
- children = model_doc.root.children.map { |child| child.name }
89
- l.error :missing_model_children unless children.include?("resources") && children.include?("build")
90
- end
91
-
92
90
  l.context "verifying build items" do |l|
93
91
  build = find_child(model_doc.root, "build")
94
92
  if build
@@ -105,14 +103,18 @@ class Model3mf
105
103
  end
106
104
 
107
105
  l.context "checking metadata" do |l|
106
+
108
107
  metadata = model_doc.root.css("metadata")
108
+
109
109
  metadata_names = metadata.map { |met| met['name'] }
110
110
  l.error :metadata_elements_with_same_name unless metadata_names.uniq!.nil?
111
111
 
112
112
  # metadata values allowed under default namespace (xmlns):
113
- metadata_values = ['Title', 'Designer', 'Description', 'Copyright', 'LicenseTerms', 'Rating', 'CreationDate', 'ModificationDate' ]
113
+ metadata_values = ['Title', 'Designer', 'Description', 'Copyright', 'LicenseTerms', 'Rating', 'CreationDate', 'ModificationDate']
114
114
 
115
- unless model_doc.root.namespace.href.nil? || model_doc.root.namespace_definitions.count > 1
115
+ known_namespaces = ["http://schemas.microsoft.com/3dmanufacturing/core/2015/02", "http://schemas.microsoft.com/3dmanufacturing/material/2015/02"]
116
+ only_known_namespaces = model_doc.root.namespace_definitions.all? { |ns| known_namespaces.include?(ns.href) }
117
+ unless model_doc.root.namespace.href.nil? || !only_known_namespaces
116
118
  l.error :invalid_metadata_under_defaultns unless (metadata_names - metadata_values).empty?
117
119
  end
118
120
  end
@@ -1,3 +1,3 @@
1
1
  module Ruby3mf
2
- VERSION = "0.1.17"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -2,24 +2,34 @@ require 'nokogiri'
2
2
 
3
3
  class XmlVal
4
4
 
5
- def self.validate_parse(file)
6
- doc = Nokogiri::XML(file.get_input_stream) do |config|
5
+ def self.validate_parse(xml_file, schema_name=nil)
6
+ doc = Nokogiri::XML(xml_file.get_input_stream) do |config|
7
7
  config.strict.nonet.noblanks
8
8
  end
9
- validate(file, doc)
9
+ validate(xml_file, doc, schema_name)
10
10
  doc
11
11
  end
12
12
 
13
- def self.validate(file, document)
13
+ def self.validate(file, document, schema_filename=nil)
14
14
  Log3mf.context "validations" do |l|
15
15
  l.error :invalid_language_locale if invalid_locale?(document)
16
16
  l.error :has_xml_space_attribute if space_attribute_exists?(document)
17
17
  l.error :wrong_encoding if xml_not_utf8_encoded?(document)
18
18
  l.error :dtd_not_allowed if dtd_exists?(file)
19
19
  l.error :has_commas_for_floats if bad_floating_numbers?(document)
20
+
21
+ if schema_filename
22
+ Log3mf.context "validating core schema" do |l|
23
+ xsd = Nokogiri::XML::Schema(File.read(File.join(File.dirname(__FILE__), schema_filename)))
24
+ core_schema_errors = xsd.validate(document)
25
+ core_schema_errors.each { |error| puts error } if ENV["DEBUG_XSD_VALIDATION"]
26
+ l.error :invalid_xml_core if core_schema_errors.size > 0
27
+ end
28
+ end
20
29
  end
21
30
  end
22
31
 
32
+
23
33
  def self.invalid_locale?(document)
24
34
  !document.xpath('//@xml:lang').empty? && document.xpath('//@xml:lang').text != "en-US"
25
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby3mf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.17
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Whitmarsh, Jeff Porter, and William Hertling
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-01-12 00:00:00.000000000 Z
11
+ date: 2017-01-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -147,6 +147,7 @@ files:
147
147
  - bin/folder_test.sh
148
148
  - bin/setup
149
149
  - lib/ruby3mf.rb
150
+ - lib/ruby3mf/3MFcoreSpec_1.1.xsd
150
151
  - lib/ruby3mf/content_types.rb
151
152
  - lib/ruby3mf/document.rb
152
153
  - lib/ruby3mf/edge_list.rb