ruby3mf 0.1.17 → 0.2.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
  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