xseed 1.0.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 +7 -0
- data/.github/workflows/rake.yml +16 -0
- data/.github/workflows/release.yml +25 -0
- data/.gitignore +72 -0
- data/.rspec +3 -0
- data/.rubocop.yml +11 -0
- data/.rubocop_todo.yml +432 -0
- data/CHANGELOG.adoc +446 -0
- data/Gemfile +21 -0
- data/LICENSE.adoc +29 -0
- data/README.adoc +386 -0
- data/Rakefile +11 -0
- data/examples/README.adoc +334 -0
- data/examples/advanced_usage.rb +286 -0
- data/examples/html_generation.rb +167 -0
- data/examples/parser_usage.rb +102 -0
- data/examples/schemas/person.xsd +171 -0
- data/examples/simple_generation.rb +149 -0
- data/exe/xseed +6 -0
- data/lib/xseed/cli.rb +376 -0
- data/lib/xseed/documentation/config.rb +101 -0
- data/lib/xseed/documentation/constants.rb +76 -0
- data/lib/xseed/documentation/generators/hierarchy_table_generator.rb +554 -0
- data/lib/xseed/documentation/generators/instance_sample_generator.rb +723 -0
- data/lib/xseed/documentation/generators/properties_table_generator.rb +983 -0
- data/lib/xseed/documentation/html_generator.rb +836 -0
- data/lib/xseed/documentation/html_generator.rb.bak +723 -0
- data/lib/xseed/documentation/presentation/css_generator.rb +510 -0
- data/lib/xseed/documentation/presentation/javascript_generator.rb +151 -0
- data/lib/xseed/documentation/presentation/navigation_builder.rb +169 -0
- data/lib/xseed/documentation/schema_loader.rb +121 -0
- data/lib/xseed/documentation/utils/helpers.rb +205 -0
- data/lib/xseed/documentation/utils/namespaces.rb +149 -0
- data/lib/xseed/documentation/utils/references.rb +135 -0
- data/lib/xseed/documentation/utils/strings.rb +75 -0
- data/lib/xseed/models/element_declaration.rb +144 -0
- data/lib/xseed/parser/xsd_parser.rb +192 -0
- data/lib/xseed/version.rb +5 -0
- data/lib/xseed.rb +76 -0
- data/xseed.gemspec +39 -0
- metadata +158 -0
|
@@ -0,0 +1,983 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "nokogiri"
|
|
4
|
+
require_relative "../config"
|
|
5
|
+
require_relative "../constants"
|
|
6
|
+
|
|
7
|
+
module Xseed
|
|
8
|
+
module Documentation
|
|
9
|
+
module Generators
|
|
10
|
+
# Generates HTML properties definition lists for schema components
|
|
11
|
+
# Ported from XS3P xs3p.xsl properties templates (lines 2322-3418)
|
|
12
|
+
#
|
|
13
|
+
# XS3P uses definition lists (<dl class="dl-horizontal">) not tables.
|
|
14
|
+
# Each component type generates 1-3 DLs:
|
|
15
|
+
# - Elements: Properties DL + Documentation DL
|
|
16
|
+
# - Complex Types: Used By DL + Properties DL + Documentation DL
|
|
17
|
+
# - Simple Types: Properties DL + Documentation DL
|
|
18
|
+
# - Attributes: Properties DL + Documentation DL
|
|
19
|
+
# - Attribute Groups/Groups: Used By DL + Documentation DL
|
|
20
|
+
# - Schema: Properties DL + Namespaces DL
|
|
21
|
+
class PropertiesTableGenerator
|
|
22
|
+
include Constants
|
|
23
|
+
|
|
24
|
+
attr_reader :component, :config, :schema
|
|
25
|
+
|
|
26
|
+
# Initialize the properties generator
|
|
27
|
+
#
|
|
28
|
+
# @param component [Nokogiri::XML::Element] Schema component
|
|
29
|
+
# @param config [Config] Configuration options
|
|
30
|
+
def initialize(component, config = Config.new)
|
|
31
|
+
raise ArgumentError, "Component cannot be nil" if component.nil?
|
|
32
|
+
|
|
33
|
+
@component = component
|
|
34
|
+
@config = config
|
|
35
|
+
@schema = component.document.root
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Generate HTML definition lists with component properties
|
|
39
|
+
# Returns array of DL HTML strings (1-3 DLs depending on component type)
|
|
40
|
+
#
|
|
41
|
+
# @return [Array<String>] Array of HTML DL markup strings
|
|
42
|
+
def generate
|
|
43
|
+
case component.name
|
|
44
|
+
when "schema"
|
|
45
|
+
generate_schema_properties
|
|
46
|
+
when "element"
|
|
47
|
+
generate_element_properties
|
|
48
|
+
when "complexType"
|
|
49
|
+
generate_complex_type_properties
|
|
50
|
+
when "simpleType"
|
|
51
|
+
generate_simple_type_properties
|
|
52
|
+
when "attribute"
|
|
53
|
+
generate_attribute_properties
|
|
54
|
+
when "attributeGroup", "group"
|
|
55
|
+
generate_group_properties
|
|
56
|
+
when "notation"
|
|
57
|
+
generate_notation_properties
|
|
58
|
+
else
|
|
59
|
+
[]
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
# Generate properties for schema element (xs3p.xsl lines 3088-3290)
|
|
66
|
+
# Returns: [Properties DL, Namespaces DL]
|
|
67
|
+
def generate_schema_properties
|
|
68
|
+
dls = []
|
|
69
|
+
|
|
70
|
+
# First DL: Schema properties
|
|
71
|
+
dls << build_dl do |xml|
|
|
72
|
+
# Target Namespace
|
|
73
|
+
xml.dt(class: "header") do
|
|
74
|
+
glossary_term_ref(xml, "TargetNS", "Target Namespace")
|
|
75
|
+
end
|
|
76
|
+
xml.dd(class: "") do
|
|
77
|
+
if schema["targetNamespace"]
|
|
78
|
+
xml.span(class: "targetNS") do
|
|
79
|
+
xml.text schema["targetNamespace"]
|
|
80
|
+
end
|
|
81
|
+
else
|
|
82
|
+
xml.text "None"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Version
|
|
87
|
+
if schema["version"]
|
|
88
|
+
xml.dt(class: "header") { xml.text "Version" }
|
|
89
|
+
xml.dd(class: "") { xml.text schema["version"] }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Language
|
|
93
|
+
if schema["xml:lang"]
|
|
94
|
+
xml.dt(class: "header") { xml.text "Language" }
|
|
95
|
+
xml.dd(class: "") { xml.text schema["xml:lang"] }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Element and Attribute Namespaces
|
|
99
|
+
xml.dt(class: "header") do
|
|
100
|
+
xml.text "Element and Attribute Namespaces"
|
|
101
|
+
end
|
|
102
|
+
xml.dd(class: "") do
|
|
103
|
+
xml.ul do
|
|
104
|
+
xml.li do
|
|
105
|
+
xml.text "Global element and attribute declarations belong to this schema's target namespace."
|
|
106
|
+
end
|
|
107
|
+
xml.li do
|
|
108
|
+
if schema["elementFormDefault"] == "qualified"
|
|
109
|
+
xml.text "By default, local element declarations belong to this schema's target namespace."
|
|
110
|
+
else
|
|
111
|
+
xml.text "By default, local element declarations have no namespace."
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
xml.li do
|
|
115
|
+
if schema["attributeFormDefault"] == "qualified"
|
|
116
|
+
xml.text "By default, local attribute declarations belong to this schema's target namespace."
|
|
117
|
+
else
|
|
118
|
+
xml.text "By default, local attribute declarations have no namespace."
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Schema Composition (imports, includes, redefines)
|
|
125
|
+
if has_schema_composition?
|
|
126
|
+
xml.dt(class: "header") { xml.text "Schema Composition" }
|
|
127
|
+
xml.dd(class: "") do
|
|
128
|
+
xml.ul do
|
|
129
|
+
generate_composition_info(xml)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Second DL: Declared Namespaces
|
|
136
|
+
dls << build_declared_namespaces_dl
|
|
137
|
+
|
|
138
|
+
dls
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Generate properties for element (xs3p.xsl lines 2732-2947)
|
|
142
|
+
# Returns: [Properties DL, Documentation DL]
|
|
143
|
+
def generate_element_properties
|
|
144
|
+
dls = []
|
|
145
|
+
|
|
146
|
+
# First DL: Element properties
|
|
147
|
+
dls << build_dl do |xml|
|
|
148
|
+
# Type
|
|
149
|
+
xml.dt(class: "header") { xml.text "Type" }
|
|
150
|
+
xml.dd(class: "") do
|
|
151
|
+
type_value = get_element_type
|
|
152
|
+
if type_value.start_with?("Locally-defined")
|
|
153
|
+
xml.text type_value
|
|
154
|
+
else
|
|
155
|
+
xml.span(class: "type") do
|
|
156
|
+
type_ref_link(xml, type_value)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Used By
|
|
162
|
+
used_by = find_used_by_for_element
|
|
163
|
+
if used_by.any?
|
|
164
|
+
xml.dt(class: "header") { xml.text "Used By" }
|
|
165
|
+
xml.dd(class: "") do
|
|
166
|
+
used_by.each_with_index do |type_name, idx|
|
|
167
|
+
xml.text ", " if idx.positive?
|
|
168
|
+
xml.span(class: "type") { type_ref_link(xml, type_name) }
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Nillable
|
|
174
|
+
if component["nillable"]
|
|
175
|
+
xml.dt(class: "header") do
|
|
176
|
+
glossary_term_ref(xml, "Nillable", "Nillable")
|
|
177
|
+
end
|
|
178
|
+
xml.dd(class: "") do
|
|
179
|
+
xml.text print_boolean(component["nillable"])
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Abstract
|
|
184
|
+
if component["abstract"]
|
|
185
|
+
xml.dt(class: "header") do
|
|
186
|
+
glossary_term_ref(xml, "Abstract", "Abstract")
|
|
187
|
+
end
|
|
188
|
+
xml.dd(class: "") do
|
|
189
|
+
xml.text print_boolean(component["abstract"])
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Default Value
|
|
194
|
+
if component["default"]
|
|
195
|
+
xml.dt(class: "header") { xml.text "Default Value" }
|
|
196
|
+
xml.dd(class: "") { xml.text component["default"] }
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Fixed Value
|
|
200
|
+
if component["fixed"]
|
|
201
|
+
xml.dt(class: "header") { xml.text "Fixed Value" }
|
|
202
|
+
xml.dd(class: "") { xml.text component["fixed"] }
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Final (Substitution Group Exclusions)
|
|
206
|
+
final_value = get_final_value
|
|
207
|
+
if final_value && !final_value.empty?
|
|
208
|
+
xml.dt(class: "header") do
|
|
209
|
+
glossary_term_ref(xml, "ElemFinal",
|
|
210
|
+
"Substitution Group Exclusions")
|
|
211
|
+
end
|
|
212
|
+
xml.dd(class: "") { xml.text final_value }
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Block (Disallowed Substitutions)
|
|
216
|
+
block_value = get_block_value
|
|
217
|
+
if block_value && !block_value.empty?
|
|
218
|
+
xml.dt(class: "header") do
|
|
219
|
+
glossary_term_ref(xml, "ElemBlock", "Disallowed Substitutions")
|
|
220
|
+
end
|
|
221
|
+
xml.dd(class: "") { xml.text block_value }
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Second DL: Documentation
|
|
226
|
+
dls << generate_documentation_dl
|
|
227
|
+
|
|
228
|
+
dls.compact
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Generate properties for complex type (xs3p.xsl lines 2547-2726)
|
|
232
|
+
# Returns: [Super-types DL, Used By DL, Properties DL, Documentation DL]
|
|
233
|
+
def generate_complex_type_properties
|
|
234
|
+
dls = []
|
|
235
|
+
|
|
236
|
+
# First DL: Super-types (if has extension/restriction)
|
|
237
|
+
base_type = get_complex_type_base
|
|
238
|
+
if base_type
|
|
239
|
+
dls << build_dl do |xml|
|
|
240
|
+
xml.dt(class: "header") { xml.text "Super-types:" }
|
|
241
|
+
xml.dd(class: "") do
|
|
242
|
+
xml.span(class: "type") { type_ref_link(xml, base_type) }
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Second DL: Used By (if applicable)
|
|
248
|
+
used_by = find_used_by_for_type
|
|
249
|
+
if used_by.any?
|
|
250
|
+
dls << build_dl do |xml|
|
|
251
|
+
xml.dt(class: "header") { xml.text "Used By" }
|
|
252
|
+
xml.dd(class: "") do
|
|
253
|
+
used_by.each_with_index do |elem_name, idx|
|
|
254
|
+
xml.text ", " if idx.positive?
|
|
255
|
+
xml.span(class: "type") { element_ref_link(xml, elem_name) }
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Third DL: Complex type properties (ONLY if has abstract/final/block)
|
|
262
|
+
if has_complex_type_properties?
|
|
263
|
+
dls << build_dl do |xml|
|
|
264
|
+
# Abstract
|
|
265
|
+
if component["abstract"]
|
|
266
|
+
xml.dt(class: "header") do
|
|
267
|
+
glossary_term_ref(xml, "Abstract", "Abstract")
|
|
268
|
+
end
|
|
269
|
+
xml.dd(class: "") do
|
|
270
|
+
xml.text print_boolean(component["abstract"])
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Final (Prohibited Derivations)
|
|
275
|
+
final_value = get_derivation_set(component["final"] || schema["finalDefault"])
|
|
276
|
+
unless final_value.empty?
|
|
277
|
+
xml.dt(class: "header") do
|
|
278
|
+
glossary_term_ref(xml, "TypeFinal", "Prohibited Derivations")
|
|
279
|
+
end
|
|
280
|
+
xml.dd(class: "") { xml.text final_value }
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Block (Prohibited Substitutions)
|
|
284
|
+
block_value = get_derivation_set(component["block"] || schema["blockDefault"])
|
|
285
|
+
unless block_value.empty?
|
|
286
|
+
xml.dt(class: "header") do
|
|
287
|
+
glossary_term_ref(xml, "TypeBlock",
|
|
288
|
+
"Prohibited Substitutions")
|
|
289
|
+
end
|
|
290
|
+
xml.dd(class: "") { xml.text block_value }
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# Fourth DL: Documentation
|
|
296
|
+
dls << generate_documentation_dl
|
|
297
|
+
|
|
298
|
+
dls.compact
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Get base type for complex type (from extension or restriction)
|
|
302
|
+
# Returns base type name or nil
|
|
303
|
+
def get_complex_type_base
|
|
304
|
+
# Check for complexContent/extension
|
|
305
|
+
extension = component.at_xpath("xsd:complexContent/xsd:extension",
|
|
306
|
+
"xsd" => XSD_NS)
|
|
307
|
+
return extension["base"] if extension
|
|
308
|
+
|
|
309
|
+
# Check for complexContent/restriction
|
|
310
|
+
restriction = component.at_xpath("xsd:complexContent/xsd:restriction",
|
|
311
|
+
"xsd" => XSD_NS)
|
|
312
|
+
return restriction["base"] if restriction
|
|
313
|
+
|
|
314
|
+
# Check for simpleContent/extension
|
|
315
|
+
extension = component.at_xpath("xsd:simpleContent/xsd:extension",
|
|
316
|
+
"xsd" => XSD_NS)
|
|
317
|
+
return extension["base"] if extension
|
|
318
|
+
|
|
319
|
+
# Check for simpleContent/restriction
|
|
320
|
+
restriction = component.at_xpath("xsd:simpleContent/xsd:restriction",
|
|
321
|
+
"xsd" => XSD_NS)
|
|
322
|
+
restriction["base"] if restriction
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# Check if complex type has properties worth displaying (follows XS3P logic)
|
|
326
|
+
# Only generate Properties DL if has abstract/final/block attributes
|
|
327
|
+
def has_complex_type_properties?
|
|
328
|
+
return true if component["abstract"]
|
|
329
|
+
|
|
330
|
+
final_value = get_derivation_set(component["final"] || schema["finalDefault"])
|
|
331
|
+
return true unless final_value.empty?
|
|
332
|
+
|
|
333
|
+
block_value = get_derivation_set(component["block"] || schema["blockDefault"])
|
|
334
|
+
!block_value.empty?
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# Generate properties for simple type (xs3p.xsl lines 3297-3412)
|
|
338
|
+
# Returns: [Properties DL, Documentation DL]
|
|
339
|
+
def generate_simple_type_properties
|
|
340
|
+
dls = []
|
|
341
|
+
|
|
342
|
+
# First DL: Simple type properties
|
|
343
|
+
dls << build_dl do |xml|
|
|
344
|
+
# Content (with facets)
|
|
345
|
+
xml.dt(class: "header") { xml.text "Content" }
|
|
346
|
+
xml.dd(class: "") do
|
|
347
|
+
print_simple_constraints(xml)
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
# Final (Prohibited Derivations)
|
|
351
|
+
final_value = get_simple_derivation_set(component["final"] || schema["finalDefault"])
|
|
352
|
+
unless final_value.empty?
|
|
353
|
+
xml.dt(class: "header") do
|
|
354
|
+
glossary_term_ref(xml, "TypeFinal", "Prohibited Derivations")
|
|
355
|
+
end
|
|
356
|
+
xml.dd(class: "") { xml.text final_value }
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# Second DL: Documentation
|
|
361
|
+
dls << generate_documentation_dl
|
|
362
|
+
|
|
363
|
+
dls.compact
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# Generate properties for attribute (xs3p.xsl lines 2322-2435)
|
|
367
|
+
# Returns: [Properties DL, Documentation DL]
|
|
368
|
+
def generate_attribute_properties
|
|
369
|
+
dls = []
|
|
370
|
+
|
|
371
|
+
# First DL: Attribute properties
|
|
372
|
+
dls << build_dl do |xml|
|
|
373
|
+
# Type
|
|
374
|
+
xml.dt(class: "header") { xml.text "Type" }
|
|
375
|
+
xml.dd(class: "") do
|
|
376
|
+
type_value = get_attribute_type
|
|
377
|
+
if type_value.start_with?("Locally-defined")
|
|
378
|
+
xml.text type_value
|
|
379
|
+
else
|
|
380
|
+
xml.span(class: "type") { type_ref_link(xml, type_value) }
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# Default Value
|
|
385
|
+
if component["default"]
|
|
386
|
+
xml.dt(class: "header") { xml.text "Default Value" }
|
|
387
|
+
xml.dd(class: "") { xml.text component["default"] }
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
# Fixed Value
|
|
391
|
+
if component["fixed"]
|
|
392
|
+
xml.dt(class: "header") { xml.text "Fixed Value" }
|
|
393
|
+
xml.dd(class: "") { xml.text component["fixed"] }
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
# Second DL: Documentation
|
|
398
|
+
dls << generate_documentation_dl
|
|
399
|
+
|
|
400
|
+
dls.compact
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
# Generate properties for attribute group or model group (xs3p.xsl lines 2441-2541)
|
|
404
|
+
# Returns: [Used By DL (optional), Documentation DL]
|
|
405
|
+
def generate_group_properties
|
|
406
|
+
dls = []
|
|
407
|
+
|
|
408
|
+
# First DL: Used By (if applicable)
|
|
409
|
+
if component.name == "attributeGroup"
|
|
410
|
+
used_by = find_used_by_for_attribute_group
|
|
411
|
+
if used_by.any?
|
|
412
|
+
dls << build_dl do |xml|
|
|
413
|
+
xml.dt(class: "header") { xml.text "Used By" }
|
|
414
|
+
xml.dd(class: "") do
|
|
415
|
+
used_by.each_with_index do |type_name, idx|
|
|
416
|
+
xml.text ", " if idx.positive?
|
|
417
|
+
xml.span(class: "type") { type_ref_link(xml, type_name) }
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
# Second DL: Documentation
|
|
425
|
+
dls << generate_documentation_dl
|
|
426
|
+
|
|
427
|
+
dls.compact
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
# Generate properties for notation (xs3p.xsl lines 2989-3082)
|
|
431
|
+
# Returns: [Properties DL, Documentation DL]
|
|
432
|
+
def generate_notation_properties
|
|
433
|
+
dls = []
|
|
434
|
+
|
|
435
|
+
# First DL: Notation properties
|
|
436
|
+
dls << build_dl do |xml|
|
|
437
|
+
# Public Identifier
|
|
438
|
+
xml.dt(class: "header") { xml.text "Public Identifier" }
|
|
439
|
+
xml.dd(class: "") { xml.text component["public"] }
|
|
440
|
+
|
|
441
|
+
# System Identifier
|
|
442
|
+
if component["system"]
|
|
443
|
+
xml.dt(class: "header") { xml.text "System Identifier" }
|
|
444
|
+
xml.dd(class: "") { xml.text component["system"] }
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
# Second DL: Documentation
|
|
449
|
+
dls << generate_documentation_dl
|
|
450
|
+
|
|
451
|
+
dls.compact
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
# Generate documentation DL for any component
|
|
455
|
+
# Returns nil if no documentation exists
|
|
456
|
+
def generate_documentation_dl
|
|
457
|
+
doc_content = extract_documentation
|
|
458
|
+
return nil unless doc_content
|
|
459
|
+
|
|
460
|
+
build_dl do |xml|
|
|
461
|
+
xml.dt { xml.text "Documentation" }
|
|
462
|
+
xml.dd do
|
|
463
|
+
xml.div(class: "annotation documentation",
|
|
464
|
+
id: "wdoc-#{component.object_id}") do
|
|
465
|
+
xml.div(class: "hidden",
|
|
466
|
+
id: "#{component.object_id}-doc-raw") do
|
|
467
|
+
xml.text doc_content
|
|
468
|
+
end
|
|
469
|
+
xml.div(class: "xs3p-doc", id: "#{component.object_id}-doc") do
|
|
470
|
+
xml.text " "
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
# Generate declared namespaces DL for schema
|
|
478
|
+
def build_declared_namespaces_dl
|
|
479
|
+
build_dl do |xml|
|
|
480
|
+
# Header row
|
|
481
|
+
xml.dt(class: "header") { xml.text "Prefix" }
|
|
482
|
+
xml.dd(class: "header") { xml.text "Namespace" }
|
|
483
|
+
|
|
484
|
+
# Default namespace
|
|
485
|
+
default_ns = schema.namespaces["xmlns"]
|
|
486
|
+
if default_ns
|
|
487
|
+
xml.dt(class: "") do
|
|
488
|
+
xml.a(id: "ns_") { xml.text "Default namespace" }
|
|
489
|
+
end
|
|
490
|
+
xml.dd(class: "") do
|
|
491
|
+
if default_ns == schema["targetNamespace"]
|
|
492
|
+
xml.span(class: "targetNS") { xml.text default_ns }
|
|
493
|
+
else
|
|
494
|
+
xml.text default_ns
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
# Namespaces with prefixes
|
|
500
|
+
schema.namespaces.each do |prefix_key, namespace_uri|
|
|
501
|
+
next if prefix_key == "xmlns" # Skip default namespace
|
|
502
|
+
|
|
503
|
+
prefix = prefix_key.sub("xmlns:", "")
|
|
504
|
+
xml.dt(class: "") do
|
|
505
|
+
xml.a(id: "ns_#{prefix}") { xml.text prefix }
|
|
506
|
+
end
|
|
507
|
+
xml.dd(class: "") do
|
|
508
|
+
if namespace_uri == schema["targetNamespace"]
|
|
509
|
+
xml.span(class: "targetNS") { xml.text namespace_uri }
|
|
510
|
+
else
|
|
511
|
+
xml.text namespace_uri
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
end
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
# Build a definition list with given content
|
|
519
|
+
def build_dl
|
|
520
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
|
521
|
+
xml.dl(class: "dl-horizontal") do
|
|
522
|
+
yield(xml)
|
|
523
|
+
end
|
|
524
|
+
end
|
|
525
|
+
builder.doc.root.to_html
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
# Print simple constraints for simple types (xs3p.xsl lines 3573-3813)
|
|
529
|
+
def print_simple_constraints(xml)
|
|
530
|
+
restriction = component.at_xpath("xsd:restriction", "xsd" => XSD_NS)
|
|
531
|
+
list_elem = component.at_xpath("xsd:list", "xsd" => XSD_NS)
|
|
532
|
+
union_elem = component.at_xpath("xsd:union", "xsd" => XSD_NS)
|
|
533
|
+
|
|
534
|
+
if restriction
|
|
535
|
+
print_simple_restriction(xml, restriction)
|
|
536
|
+
elsif list_elem
|
|
537
|
+
xml.ul do
|
|
538
|
+
xml.li do
|
|
539
|
+
xml.text "List of: "
|
|
540
|
+
if list_elem["itemType"]
|
|
541
|
+
type_ref_link(xml, list_elem["itemType"])
|
|
542
|
+
else
|
|
543
|
+
# Locally-defined item type
|
|
544
|
+
xml.text "Locally defined type"
|
|
545
|
+
end
|
|
546
|
+
end
|
|
547
|
+
end
|
|
548
|
+
elsif union_elem
|
|
549
|
+
xml.ul do
|
|
550
|
+
xml.li do
|
|
551
|
+
xml.text "Union of following types: "
|
|
552
|
+
xml.ul do
|
|
553
|
+
union_elem["memberTypes"]&.split&.each do |member_type|
|
|
554
|
+
xml.li { type_ref_link(xml, member_type) }
|
|
555
|
+
end
|
|
556
|
+
# Locally-defined member types
|
|
557
|
+
union_elem.xpath("xsd:simpleType", "xsd" => XSD_NS).each do
|
|
558
|
+
xml.li { xml.text "Locally defined type" }
|
|
559
|
+
end
|
|
560
|
+
end
|
|
561
|
+
end
|
|
562
|
+
end
|
|
563
|
+
end
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
# Print simple restriction (xs3p.xsl lines 3651-3734)
|
|
567
|
+
def print_simple_restriction(xml, restriction)
|
|
568
|
+
base_type = restriction["base"]
|
|
569
|
+
|
|
570
|
+
# Base type
|
|
571
|
+
if base_type
|
|
572
|
+
base_name = base_type.include?(":") ? base_type.split(":").last : base_type
|
|
573
|
+
base_ns = get_namespace_for_prefix(base_type.split(":").first) if base_type.include?(":")
|
|
574
|
+
|
|
575
|
+
if base_ns == XSD_NS || !base_type.include?(":")
|
|
576
|
+
xml.ul do
|
|
577
|
+
xml.li do
|
|
578
|
+
xml.text "Base XSD Type: "
|
|
579
|
+
xml.text base_name
|
|
580
|
+
end
|
|
581
|
+
end
|
|
582
|
+
else
|
|
583
|
+
# Look up the base type and recurse
|
|
584
|
+
base_type_elem = schema.at_xpath(
|
|
585
|
+
"//xsd:simpleType[@name='#{base_name}']", "xsd" => XSD_NS
|
|
586
|
+
)
|
|
587
|
+
if base_type_elem
|
|
588
|
+
base_gen = self.class.new(base_type_elem, config)
|
|
589
|
+
base_gen.print_simple_constraints(xml)
|
|
590
|
+
end
|
|
591
|
+
end
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
# Facets
|
|
595
|
+
print_facets(xml, restriction)
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
# Print facets from restriction (xs3p.xsl lines 3737-3811)
|
|
599
|
+
def print_facets(xml, restriction)
|
|
600
|
+
facets_list = []
|
|
601
|
+
|
|
602
|
+
# Enumeration
|
|
603
|
+
enums = restriction.xpath("xsd:enumeration", "xsd" => XSD_NS)
|
|
604
|
+
if enums.any?
|
|
605
|
+
facets_list << ->(xml) do
|
|
606
|
+
xml.em { xml.text "value" }
|
|
607
|
+
xml.text " comes from list: {"
|
|
608
|
+
enums.each_with_index do |enum, idx|
|
|
609
|
+
xml.text "|" if idx.positive?
|
|
610
|
+
xml.text "'#{enum['value']}'"
|
|
611
|
+
end
|
|
612
|
+
xml.text "}"
|
|
613
|
+
end
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
# Pattern
|
|
617
|
+
pattern = restriction.at_xpath("xsd:pattern", "xsd" => XSD_NS)
|
|
618
|
+
if pattern
|
|
619
|
+
facets_list << ->(xml) do
|
|
620
|
+
xml.em { xml.text "pattern" }
|
|
621
|
+
xml.text " = #{pattern['value']}"
|
|
622
|
+
end
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
# Range facets
|
|
626
|
+
range_facet = get_range_facet(restriction)
|
|
627
|
+
if range_facet
|
|
628
|
+
facets_list << ->(xml) { xml << range_facet }
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
# Total digits
|
|
632
|
+
total_digits = restriction.at_xpath("xsd:totalDigits",
|
|
633
|
+
"xsd" => XSD_NS)
|
|
634
|
+
if total_digits
|
|
635
|
+
facets_list << ->(xml) do
|
|
636
|
+
xml.em { xml.text "total no. of digits" }
|
|
637
|
+
xml.text " = #{total_digits['value']}"
|
|
638
|
+
end
|
|
639
|
+
end
|
|
640
|
+
|
|
641
|
+
# Fraction digits
|
|
642
|
+
fraction_digits = restriction.at_xpath("xsd:fractionDigits",
|
|
643
|
+
"xsd" => XSD_NS)
|
|
644
|
+
if fraction_digits
|
|
645
|
+
facets_list << ->(xml) do
|
|
646
|
+
xml.em { xml.text "no. of fraction digits" }
|
|
647
|
+
xml.text " = #{fraction_digits['value']}"
|
|
648
|
+
end
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
# Length facets
|
|
652
|
+
length_facet = get_length_facet(restriction)
|
|
653
|
+
if length_facet
|
|
654
|
+
facets_list << ->(xml) { xml << length_facet }
|
|
655
|
+
end
|
|
656
|
+
|
|
657
|
+
# Whitespace
|
|
658
|
+
whitespace = restriction.at_xpath("xsd:whiteSpace", "xsd" => XSD_NS)
|
|
659
|
+
if whitespace
|
|
660
|
+
facets_list << ->(xml) do
|
|
661
|
+
xml.em { xml.text "Whitespace policy: " }
|
|
662
|
+
policy_code = case whitespace["value"]
|
|
663
|
+
when "preserve" then "PreserveWS"
|
|
664
|
+
when "replace" then "ReplaceWS"
|
|
665
|
+
when "collapse" then "CollapseWS"
|
|
666
|
+
end
|
|
667
|
+
if policy_code
|
|
668
|
+
glossary_term_ref(xml, policy_code,
|
|
669
|
+
whitespace["value"])
|
|
670
|
+
end
|
|
671
|
+
end
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
# Output facets as list if any exist
|
|
675
|
+
return if facets_list.empty?
|
|
676
|
+
|
|
677
|
+
xml.ul do
|
|
678
|
+
facets_list.each do |facet_lambda|
|
|
679
|
+
xml.li { facet_lambda.call(xml) }
|
|
680
|
+
end
|
|
681
|
+
end
|
|
682
|
+
end
|
|
683
|
+
|
|
684
|
+
# Get range facet string
|
|
685
|
+
def get_range_facet(restriction)
|
|
686
|
+
min_inc = restriction.at_xpath("xsd:minInclusive", "xsd" => XSD_NS)
|
|
687
|
+
min_exc = restriction.at_xpath("xsd:minExclusive", "xsd" => XSD_NS)
|
|
688
|
+
max_inc = restriction.at_xpath("xsd:maxInclusive", "xsd" => XSD_NS)
|
|
689
|
+
max_exc = restriction.at_xpath("xsd:maxExclusive", "xsd" => XSD_NS)
|
|
690
|
+
|
|
691
|
+
return nil unless min_inc || min_exc || max_inc || max_exc
|
|
692
|
+
|
|
693
|
+
parts = []
|
|
694
|
+
if min_inc
|
|
695
|
+
parts << "#{min_inc['value']} <= <em>value</em>"
|
|
696
|
+
elsif min_exc
|
|
697
|
+
parts << "#{min_exc['value']} < <em>value</em>"
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
if max_inc
|
|
701
|
+
parts << "<em>value</em> <= #{max_inc['value']}"
|
|
702
|
+
elsif max_exc
|
|
703
|
+
parts << "<em>value</em> < #{max_exc['value']}"
|
|
704
|
+
end
|
|
705
|
+
|
|
706
|
+
parts.join(" and ")
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
# Get length facet string
|
|
710
|
+
def get_length_facet(restriction)
|
|
711
|
+
length = restriction.at_xpath("xsd:length", "xsd" => XSD_NS)
|
|
712
|
+
min_length = restriction.at_xpath("xsd:minLength", "xsd" => XSD_NS)
|
|
713
|
+
max_length = restriction.at_xpath("xsd:maxLength", "xsd" => XSD_NS)
|
|
714
|
+
|
|
715
|
+
return nil unless length || min_length || max_length
|
|
716
|
+
|
|
717
|
+
if length
|
|
718
|
+
"<em>length</em> = #{length['value']}"
|
|
719
|
+
elsif min_length && max_length
|
|
720
|
+
"#{min_length['value']} <= <em>length</em> <= #{max_length['value']}"
|
|
721
|
+
elsif min_length
|
|
722
|
+
"<em>length</em> >= #{min_length['value']}"
|
|
723
|
+
elsif max_length
|
|
724
|
+
"<em>length</em> <= #{max_length['value']}"
|
|
725
|
+
end
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
# Find elements that use this element (via ref)
|
|
729
|
+
def find_used_by_for_element
|
|
730
|
+
elem_name = component["name"]
|
|
731
|
+
return [] unless elem_name
|
|
732
|
+
|
|
733
|
+
used_by = []
|
|
734
|
+
schema.xpath("//xsd:element[@ref='#{elem_name}']",
|
|
735
|
+
"xsd" => XSD_NS).each do |ref_elem|
|
|
736
|
+
# Find containing complex type
|
|
737
|
+
parent_type = ref_elem.at_xpath("ancestor::xsd:complexType[@name]",
|
|
738
|
+
"xsd" => XSD_NS)
|
|
739
|
+
used_by << parent_type["name"] if parent_type
|
|
740
|
+
end
|
|
741
|
+
used_by.uniq
|
|
742
|
+
end
|
|
743
|
+
|
|
744
|
+
# Find elements that use this type
|
|
745
|
+
def find_used_by_for_type
|
|
746
|
+
type_name = component["name"]
|
|
747
|
+
return [] unless type_name
|
|
748
|
+
|
|
749
|
+
used_by = schema.xpath(
|
|
750
|
+
"//xsd:element[@type='#{type_name}'] | //xsd:element[@type='#{get_prefixed_name(type_name)}']", "xsd" => XSD_NS
|
|
751
|
+
).map do |elem|
|
|
752
|
+
elem["name"]
|
|
753
|
+
end
|
|
754
|
+
used_by.uniq.compact
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
# Find types that use this attribute group
|
|
758
|
+
def find_used_by_for_attribute_group
|
|
759
|
+
group_name = component["name"]
|
|
760
|
+
return [] unless group_name
|
|
761
|
+
|
|
762
|
+
used_by = []
|
|
763
|
+
schema.xpath("//xsd:attributeGroup[@ref='#{group_name}']",
|
|
764
|
+
"xsd" => XSD_NS).each do |ref|
|
|
765
|
+
parent_type = ref.at_xpath("ancestor::xsd:complexType[@name]",
|
|
766
|
+
"xsd" => XSD_NS)
|
|
767
|
+
used_by << parent_type["name"] if parent_type
|
|
768
|
+
end
|
|
769
|
+
used_by.uniq
|
|
770
|
+
end
|
|
771
|
+
|
|
772
|
+
# Get element type
|
|
773
|
+
def get_element_type
|
|
774
|
+
if component.at_xpath("xsd:simpleType", "xsd" => XSD_NS)
|
|
775
|
+
"Locally-defined simple type"
|
|
776
|
+
elsif component.at_xpath("xsd:complexType", "xsd" => XSD_NS)
|
|
777
|
+
"Locally-defined complex type"
|
|
778
|
+
elsif component["type"]
|
|
779
|
+
component["type"]
|
|
780
|
+
else
|
|
781
|
+
"anyType"
|
|
782
|
+
end
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
# Get attribute type
|
|
786
|
+
def get_attribute_type
|
|
787
|
+
if component.at_xpath("xsd:simpleType", "xsd" => XSD_NS)
|
|
788
|
+
"Locally-defined simple type"
|
|
789
|
+
elsif component["type"]
|
|
790
|
+
component["type"]
|
|
791
|
+
else
|
|
792
|
+
"anySimpleType"
|
|
793
|
+
end
|
|
794
|
+
end
|
|
795
|
+
|
|
796
|
+
# Get final value for element
|
|
797
|
+
def get_final_value
|
|
798
|
+
final_attr = component["final"] || schema["finalDefault"]
|
|
799
|
+
translate_derivation_set(final_attr)
|
|
800
|
+
end
|
|
801
|
+
|
|
802
|
+
# Get block value for element
|
|
803
|
+
def get_block_value
|
|
804
|
+
block_attr = component["block"] || schema["blockDefault"]
|
|
805
|
+
translate_block_set(block_attr)
|
|
806
|
+
end
|
|
807
|
+
|
|
808
|
+
# Translate derivation set (#all -> full list)
|
|
809
|
+
def get_derivation_set(value)
|
|
810
|
+
return "" unless value
|
|
811
|
+
|
|
812
|
+
if value == "#all"
|
|
813
|
+
"restriction, extension"
|
|
814
|
+
else
|
|
815
|
+
value
|
|
816
|
+
end
|
|
817
|
+
end
|
|
818
|
+
|
|
819
|
+
# Translate simple derivation set (#all -> full list)
|
|
820
|
+
def get_simple_derivation_set(value)
|
|
821
|
+
return "" unless value
|
|
822
|
+
|
|
823
|
+
if value == "#all"
|
|
824
|
+
"restriction, list, union"
|
|
825
|
+
else
|
|
826
|
+
value
|
|
827
|
+
end
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
# Translate block set (#all -> full list for elements)
|
|
831
|
+
def translate_block_set(value)
|
|
832
|
+
return "" unless value
|
|
833
|
+
|
|
834
|
+
if value == "#all"
|
|
835
|
+
"restriction, extension, substitution"
|
|
836
|
+
else
|
|
837
|
+
value
|
|
838
|
+
end
|
|
839
|
+
end
|
|
840
|
+
|
|
841
|
+
# Translate derivation set for elements/types
|
|
842
|
+
def translate_derivation_set(value)
|
|
843
|
+
return "" unless value
|
|
844
|
+
|
|
845
|
+
if value == "#all"
|
|
846
|
+
"restriction, extension"
|
|
847
|
+
else
|
|
848
|
+
value
|
|
849
|
+
end
|
|
850
|
+
end
|
|
851
|
+
|
|
852
|
+
# Print boolean value as yes/no
|
|
853
|
+
def print_boolean(bool_value)
|
|
854
|
+
return "no" unless bool_value
|
|
855
|
+
|
|
856
|
+
normalized = bool_value.to_s.downcase
|
|
857
|
+
["true", "1"].include?(normalized) ? "yes" : "no"
|
|
858
|
+
end
|
|
859
|
+
|
|
860
|
+
# Check if schema has imports, includes, or redefines
|
|
861
|
+
def has_schema_composition?
|
|
862
|
+
schema.at_xpath("xsd:import | xsd:include | xsd:redefine",
|
|
863
|
+
"xsd" => XSD_NS)
|
|
864
|
+
end
|
|
865
|
+
|
|
866
|
+
# Generate schema composition info
|
|
867
|
+
def generate_composition_info(xml)
|
|
868
|
+
# Imports
|
|
869
|
+
imports = schema.xpath("xsd:import", "xsd" => XSD_NS)
|
|
870
|
+
if imports.any?
|
|
871
|
+
xml.li do
|
|
872
|
+
xml.text "This schema imports schema(s) from the following namespace(s):"
|
|
873
|
+
xml.ul do
|
|
874
|
+
imports.each do |import_elem|
|
|
875
|
+
xml.li do
|
|
876
|
+
xml.em { xml.text import_elem["namespace"] }
|
|
877
|
+
if import_elem["schemaLocation"]
|
|
878
|
+
xml.text " (at #{import_elem['schemaLocation']})"
|
|
879
|
+
end
|
|
880
|
+
end
|
|
881
|
+
end
|
|
882
|
+
end
|
|
883
|
+
end
|
|
884
|
+
end
|
|
885
|
+
|
|
886
|
+
# Includes
|
|
887
|
+
includes = schema.xpath("xsd:include", "xsd" => XSD_NS)
|
|
888
|
+
if includes.any?
|
|
889
|
+
xml.li do
|
|
890
|
+
xml.text "This schema includes components from the following schema document(s):"
|
|
891
|
+
xml.ul do
|
|
892
|
+
includes.each do |include_elem|
|
|
893
|
+
xml.li { xml.text include_elem["schemaLocation"] }
|
|
894
|
+
end
|
|
895
|
+
end
|
|
896
|
+
end
|
|
897
|
+
end
|
|
898
|
+
|
|
899
|
+
# Redefines
|
|
900
|
+
redefines = schema.xpath("xsd:redefine", "xsd" => XSD_NS)
|
|
901
|
+
return unless redefines.any?
|
|
902
|
+
|
|
903
|
+
xml.li do
|
|
904
|
+
xml.text "This schema includes components from the following schema document(s), where some of the components have been redefined:"
|
|
905
|
+
xml.ul do
|
|
906
|
+
redefines.each do |redefine_elem|
|
|
907
|
+
xml.li { xml.text redefine_elem["schemaLocation"] }
|
|
908
|
+
end
|
|
909
|
+
end
|
|
910
|
+
xml.text "See "
|
|
911
|
+
xml.a(href: "#Redefinitions") do
|
|
912
|
+
xml.text "Redefined Schema Components"
|
|
913
|
+
end
|
|
914
|
+
xml.text " section."
|
|
915
|
+
end
|
|
916
|
+
end
|
|
917
|
+
|
|
918
|
+
# Extract documentation text
|
|
919
|
+
def extract_documentation
|
|
920
|
+
doc_node = component.at_xpath("xsd:annotation/xsd:documentation",
|
|
921
|
+
"xsd" => XSD_NS)
|
|
922
|
+
doc_node&.text&.strip
|
|
923
|
+
end
|
|
924
|
+
|
|
925
|
+
# Generate glossary term reference link
|
|
926
|
+
def glossary_term_ref(xml, code, term)
|
|
927
|
+
if config.print_glossary
|
|
928
|
+
xml.a(title: "Look up '#{term}' in glossary",
|
|
929
|
+
href: "#term_#{code}") do
|
|
930
|
+
xml.text term
|
|
931
|
+
end
|
|
932
|
+
else
|
|
933
|
+
xml.text term
|
|
934
|
+
end
|
|
935
|
+
end
|
|
936
|
+
|
|
937
|
+
# Generate type reference link
|
|
938
|
+
def type_ref_link(xml, type_ref)
|
|
939
|
+
type_name = type_ref.include?(":") ? type_ref.split(":").last : type_ref
|
|
940
|
+
xml.a(title: "Jump to \"#{type_name}\" type definition.",
|
|
941
|
+
href: "#type_#{type_name}") do
|
|
942
|
+
xml.text type_name
|
|
943
|
+
end
|
|
944
|
+
end
|
|
945
|
+
|
|
946
|
+
# Generate element reference link
|
|
947
|
+
def element_ref_link(xml, elem_ref)
|
|
948
|
+
elem_name = elem_ref.include?(":") ? elem_ref.split(":").last : elem_ref
|
|
949
|
+
xml.a(title: "Jump to \"#{elem_name}\" element declaration.",
|
|
950
|
+
href: "#element_#{elem_name}") do
|
|
951
|
+
xml.text elem_name
|
|
952
|
+
end
|
|
953
|
+
end
|
|
954
|
+
|
|
955
|
+
# Get prefixed name for type reference
|
|
956
|
+
def get_prefixed_name(name)
|
|
957
|
+
prefix = get_target_namespace_prefix
|
|
958
|
+
prefix ? "#{prefix}:#{name}" : name
|
|
959
|
+
end
|
|
960
|
+
|
|
961
|
+
# Get prefix for target namespace
|
|
962
|
+
def get_target_namespace_prefix
|
|
963
|
+
target_ns = schema["targetNamespace"]
|
|
964
|
+
return nil unless target_ns
|
|
965
|
+
|
|
966
|
+
schema.namespaces.each do |prefix_key, ns_uri|
|
|
967
|
+
next if prefix_key == "xmlns"
|
|
968
|
+
|
|
969
|
+
return prefix_key.sub("xmlns:", "") if ns_uri == target_ns
|
|
970
|
+
end
|
|
971
|
+
nil
|
|
972
|
+
end
|
|
973
|
+
|
|
974
|
+
# Get namespace URI for a given prefix
|
|
975
|
+
def get_namespace_for_prefix(prefix)
|
|
976
|
+
return nil unless prefix
|
|
977
|
+
|
|
978
|
+
schema.namespaces["xmlns:#{prefix}"]
|
|
979
|
+
end
|
|
980
|
+
end
|
|
981
|
+
end
|
|
982
|
+
end
|
|
983
|
+
end
|