xsdvi 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/LICENSE +30 -0
- data/README.adoc +317 -0
- data/exe/xsdvi +6 -0
- data/lib/xsdvi/cli.rb +163 -0
- data/lib/xsdvi/svg/generator.rb +93 -0
- data/lib/xsdvi/svg/symbol.rb +234 -0
- data/lib/xsdvi/svg/symbols/all.rb +46 -0
- data/lib/xsdvi/svg/symbols/any.rb +59 -0
- data/lib/xsdvi/svg/symbols/any_attribute.rb +58 -0
- data/lib/xsdvi/svg/symbols/attribute.rb +64 -0
- data/lib/xsdvi/svg/symbols/choice.rb +46 -0
- data/lib/xsdvi/svg/symbols/element.rb +91 -0
- data/lib/xsdvi/svg/symbols/field.rb +42 -0
- data/lib/xsdvi/svg/symbols/key.rb +46 -0
- data/lib/xsdvi/svg/symbols/keyref.rb +49 -0
- data/lib/xsdvi/svg/symbols/loop.rb +35 -0
- data/lib/xsdvi/svg/symbols/schema.rb +42 -0
- data/lib/xsdvi/svg/symbols/selector.rb +42 -0
- data/lib/xsdvi/svg/symbols/sequence.rb +48 -0
- data/lib/xsdvi/svg/symbols/unique.rb +46 -0
- data/lib/xsdvi/tree/builder.rb +31 -0
- data/lib/xsdvi/tree/element.rb +62 -0
- data/lib/xsdvi/utils/resource_loader.rb +21 -0
- data/lib/xsdvi/utils/width_calculator.rb +23 -0
- data/lib/xsdvi/utils/writer.rb +29 -0
- data/lib/xsdvi/version.rb +5 -0
- data/lib/xsdvi/xsd_handler.rb +323 -0
- data/lib/xsdvi.rb +30 -0
- data/resources/svg/defined_symbols.svg +9 -0
- data/resources/svg/doctype.txt +1 -0
- data/resources/svg/menu_buttons.svg +7 -0
- data/resources/svg/script.js +265 -0
- data/resources/svg/style.css +29 -0
- data/resources/svg/style.html +3 -0
- data/resources/svg/style.xml +1 -0
- data/resources/svg/svg_end.txt +1 -0
- data/resources/svg/svg_start.txt +1 -0
- data/resources/svg/title.txt +1 -0
- data/resources/svg/xml_declaration.xml +1 -0
- metadata +113 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../tree/element"
|
|
4
|
+
|
|
5
|
+
module Xsdvi
|
|
6
|
+
module SVG
|
|
7
|
+
# Base class for all SVG symbols
|
|
8
|
+
class Symbol < Tree::Element
|
|
9
|
+
# Process contents constants
|
|
10
|
+
PC_STRICT = 1
|
|
11
|
+
PC_SKIP = 2
|
|
12
|
+
PC_LAX = 3
|
|
13
|
+
|
|
14
|
+
# Layout constants
|
|
15
|
+
X_INDENT = 45
|
|
16
|
+
Y_INDENT = 25
|
|
17
|
+
MIN_WIDTH = 60
|
|
18
|
+
MAX_HEIGHT = 46
|
|
19
|
+
MID_HEIGHT = 31
|
|
20
|
+
MIN_HEIGHT = 21
|
|
21
|
+
|
|
22
|
+
attr_accessor :x_position, :y_position, :width, :height,
|
|
23
|
+
:start_y_position, :svg, :description
|
|
24
|
+
attr_reader :description_string_array, :y_shift,
|
|
25
|
+
:additional_height
|
|
26
|
+
|
|
27
|
+
def initialize
|
|
28
|
+
super
|
|
29
|
+
@x_position = 0
|
|
30
|
+
@y_position = 0
|
|
31
|
+
@width = 0
|
|
32
|
+
@height = 0
|
|
33
|
+
@start_y_position = 50
|
|
34
|
+
@description = []
|
|
35
|
+
@description_string_array = []
|
|
36
|
+
@y_shift = 14
|
|
37
|
+
@additional_height = 0
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def x_end
|
|
41
|
+
x_position + width
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def y_end
|
|
45
|
+
y_position + MAX_HEIGHT
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def prepare_box
|
|
49
|
+
if parent?
|
|
50
|
+
@x_position = parent.x_end + X_INDENT
|
|
51
|
+
highest = Symbol.highest_y_position || 0
|
|
52
|
+
@y_position = if first_child?
|
|
53
|
+
highest
|
|
54
|
+
else
|
|
55
|
+
highest + MAX_HEIGHT + Y_INDENT
|
|
56
|
+
end
|
|
57
|
+
else
|
|
58
|
+
@x_position = 20
|
|
59
|
+
@y_position = start_y_position
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Ensure values are integers
|
|
63
|
+
@x_position = @x_position.to_i
|
|
64
|
+
@y_position = @y_position.to_i
|
|
65
|
+
@width = calculate_width
|
|
66
|
+
@height = calculate_height
|
|
67
|
+
Symbol.highest_y_position = @y_position
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def draw
|
|
71
|
+
raise NotImplementedError, "Subclasses must implement draw method"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def calculate_width
|
|
75
|
+
MIN_WIDTH
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def calculate_height
|
|
79
|
+
MAX_HEIGHT
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
class << self
|
|
83
|
+
attr_accessor :highest_y_position, :additional_height_rest,
|
|
84
|
+
:prev_x_position, :prev_y_position
|
|
85
|
+
|
|
86
|
+
def reset_class_variables
|
|
87
|
+
@highest_y_position = 0
|
|
88
|
+
@additional_height_rest = 0
|
|
89
|
+
@prev_x_position = 0
|
|
90
|
+
@prev_y_position = 0
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
reset_class_variables
|
|
95
|
+
|
|
96
|
+
protected
|
|
97
|
+
|
|
98
|
+
def print(string)
|
|
99
|
+
svg.print(string)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def draw_g_start
|
|
103
|
+
rest = Symbol.additional_height_rest || 0
|
|
104
|
+
prev_x = Symbol.prev_x_position || 0
|
|
105
|
+
# Always include y_position as integer
|
|
106
|
+
print("<g id='#{code}' class='box' " \
|
|
107
|
+
"transform='translate(#{x_position.to_i},#{y_position.to_i})' " \
|
|
108
|
+
"data-desc-height='#{additional_height.to_i}' " \
|
|
109
|
+
"data-desc-height-rest='#{rest.to_i}' " \
|
|
110
|
+
"data-desc-x='#{prev_x.to_i}'>")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def draw_g_end
|
|
114
|
+
print("</g>\n")
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def draw_connection
|
|
118
|
+
if last_child? && !first_child?
|
|
119
|
+
y_offset = parent.y_position - y_position + (MAX_HEIGHT / 2)
|
|
120
|
+
print("<line class='connection' id='p#{code}' " \
|
|
121
|
+
"x1='#{10 - X_INDENT}' y1='#{y_offset}' " \
|
|
122
|
+
"x2='#{10 - X_INDENT}' y2='#{-15 - Y_INDENT}'/>")
|
|
123
|
+
print("<path class='connection' " \
|
|
124
|
+
"d='M#{10 - X_INDENT},#{-15 - Y_INDENT} " \
|
|
125
|
+
"Q#{10 - X_INDENT},15 0,#{MAX_HEIGHT / 2}'/>")
|
|
126
|
+
elsif parent?
|
|
127
|
+
print("<line class='connection' " \
|
|
128
|
+
"x1='#{10 - X_INDENT}' y1='#{MAX_HEIGHT / 2}' " \
|
|
129
|
+
"x2='0' y2='#{MAX_HEIGHT / 2}'/>")
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def draw_use
|
|
134
|
+
return unless children?
|
|
135
|
+
|
|
136
|
+
code_str = code
|
|
137
|
+
print("<use x='#{width - 1}' y='#{(MAX_HEIGHT / 2) - 6}' " \
|
|
138
|
+
"xlink:href='#minus' id='s#{code_str}' " \
|
|
139
|
+
"onclick='show(\"#{code_str}\")'/>")
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def draw_mouseover
|
|
143
|
+
print("onmouseover='makeVisible(\"#{code}\")' " \
|
|
144
|
+
"onmouseout='makeHidden(\"#{code}\")'/>")
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def process_description
|
|
148
|
+
return if description.empty?
|
|
149
|
+
|
|
150
|
+
wrap_length = (width / 5.5).round
|
|
151
|
+
strings_with_breaks = []
|
|
152
|
+
|
|
153
|
+
description.each do |desc_string|
|
|
154
|
+
# WordUtils.wrap returns string with \n embedded, then split
|
|
155
|
+
wrapped_string = word_utils_wrap(desc_string, wrap_length)
|
|
156
|
+
wrapped_lines = wrapped_string.split("\n")
|
|
157
|
+
strings_with_breaks.concat(wrapped_lines)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
@description_string_array = strings_with_breaks
|
|
161
|
+
@additional_height = y_shift * strings_with_breaks.size
|
|
162
|
+
|
|
163
|
+
prev_y = Symbol.prev_y_position || 0
|
|
164
|
+
curr_y = y_position || 0
|
|
165
|
+
|
|
166
|
+
if curr_y > prev_y && prev_y != 0
|
|
167
|
+
rest = Symbol.additional_height_rest || 0
|
|
168
|
+
rest -= height
|
|
169
|
+
rest = 0 if rest.negative?
|
|
170
|
+
rest = additional_height if rest < additional_height
|
|
171
|
+
Symbol.additional_height_rest = rest
|
|
172
|
+
elsif additional_height != 0
|
|
173
|
+
Symbol.additional_height_rest = additional_height
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
Symbol.prev_x_position = x_position unless description.empty?
|
|
177
|
+
Symbol.prev_y_position = y_position
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def draw_description(y_start)
|
|
181
|
+
description_string_array.each do |line|
|
|
182
|
+
y_start += y_shift
|
|
183
|
+
escaped_line = line.gsub("<", "<").gsub(">", ">")
|
|
184
|
+
print("<text x='5' y='#{y_start}' class='desc'>#{escaped_line}</text>")
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Apache Commons WordUtils.wrap(str, wrapLength, newLineStr, wrapLongWords)
|
|
189
|
+
# Wraps text at wrapLength, inserting newLineStr, optionally breaking long words
|
|
190
|
+
def word_utils_wrap(input, wrap_length)
|
|
191
|
+
return input if input.nil? || wrap_length < 1
|
|
192
|
+
|
|
193
|
+
input_line_length = input.length
|
|
194
|
+
return input if input_line_length <= wrap_length
|
|
195
|
+
|
|
196
|
+
result = []
|
|
197
|
+
offset = 0
|
|
198
|
+
|
|
199
|
+
while offset < input_line_length
|
|
200
|
+
# Handle existing newline in input
|
|
201
|
+
space_idx = input.index("\n", offset)
|
|
202
|
+
if space_idx && space_idx < wrap_length + offset
|
|
203
|
+
# There's a newline before wrap point
|
|
204
|
+
result << input[offset...space_idx]
|
|
205
|
+
offset = space_idx + 1
|
|
206
|
+
next
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Find wrap point
|
|
210
|
+
if input_line_length - offset <= wrap_length
|
|
211
|
+
# Rest of string fits
|
|
212
|
+
result << input[offset..]
|
|
213
|
+
break
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# Need to wrap - find last space before wrap_length
|
|
217
|
+
space_idx = input.rindex(" ", offset + wrap_length)
|
|
218
|
+
|
|
219
|
+
if space_idx && space_idx >= offset
|
|
220
|
+
# Found space to break at
|
|
221
|
+
result << input[offset...space_idx]
|
|
222
|
+
offset = space_idx + 1
|
|
223
|
+
else
|
|
224
|
+
# No space found - break at wrap_length (wrapLongWords=true)
|
|
225
|
+
result << input[offset...(offset + wrap_length)]
|
|
226
|
+
offset += wrap_length
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
result.join("\n")
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../symbol"
|
|
4
|
+
|
|
5
|
+
module Xsdvi
|
|
6
|
+
module SVG
|
|
7
|
+
module Symbols
|
|
8
|
+
# Symbol for XSD all compositor
|
|
9
|
+
class All < Symbol
|
|
10
|
+
attr_accessor :cardinality
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
super
|
|
14
|
+
@cardinality = nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def draw
|
|
18
|
+
process_description
|
|
19
|
+
draw_g_start
|
|
20
|
+
print("<rect class='boxcompositor' x='0' y='8' width='#{width}' " \
|
|
21
|
+
"height='#{height}' rx='9'/>")
|
|
22
|
+
print("<circle cx='#{(width / 2) + 12}' cy='14' r='2'/>")
|
|
23
|
+
print("<circle cx='#{(width / 2) + 12}' cy='23' r='2'/>")
|
|
24
|
+
print("<circle cx='#{(width / 2) + 12}' cy='32' r='2'/>")
|
|
25
|
+
print("<text class='small' x='#{width / 2}' y='17'>∀</text>")
|
|
26
|
+
print("<line x1='#{(width / 2) + 12}' y1='14' x2='#{(width / 2) + 12}' y2='32'/>")
|
|
27
|
+
print("<text x='5' y='52'>#{cardinality}</text>") if cardinality
|
|
28
|
+
draw_description(52)
|
|
29
|
+
draw_connection
|
|
30
|
+
draw_use
|
|
31
|
+
draw_g_end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def calculate_width
|
|
35
|
+
calc = Utils::WidthCalculator.new(MIN_WIDTH)
|
|
36
|
+
calc.new_width(15, cardinality)
|
|
37
|
+
calc.width
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def calculate_height
|
|
41
|
+
MID_HEIGHT
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../symbol"
|
|
4
|
+
|
|
5
|
+
module Xsdvi
|
|
6
|
+
module SVG
|
|
7
|
+
module Symbols
|
|
8
|
+
# Symbol for XSD any wildcard
|
|
9
|
+
class Any < Symbol
|
|
10
|
+
attr_accessor :namespace, :process_contents, :cardinality
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
super
|
|
14
|
+
@namespace = nil
|
|
15
|
+
@process_contents = PC_STRICT
|
|
16
|
+
@cardinality = nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def draw
|
|
20
|
+
process_description
|
|
21
|
+
draw_g_start
|
|
22
|
+
print("<rect class='shadow' x='3' y='3' width='#{width}' height='#{height}'/>")
|
|
23
|
+
print("<rect class='boxany' x='0' y='0' width='#{width}' height='#{height}'/>")
|
|
24
|
+
|
|
25
|
+
# Draw process contents boxes
|
|
26
|
+
pc_class = case process_contents
|
|
27
|
+
when PC_STRICT then "strict"
|
|
28
|
+
when PC_SKIP then "skip"
|
|
29
|
+
when PC_LAX then "lax"
|
|
30
|
+
else "strict"
|
|
31
|
+
end
|
|
32
|
+
print("<rect class='#{pc_class}' x='6' y='34' width='6' height='6'/>")
|
|
33
|
+
print("<rect class='#{pc_class}' x='16' y='34' width='6' height='6'/>")
|
|
34
|
+
print("<rect class='#{pc_class}' x='26' y='34' width='6' height='6'/>")
|
|
35
|
+
|
|
36
|
+
print("<text x='5' y='13'>#{namespace}</text>") if namespace
|
|
37
|
+
# Java shows just angle brackets <> not <any>
|
|
38
|
+
print("<text class='strong' x='5' y='27'><></text>")
|
|
39
|
+
print("<text x='5' y='59'>#{cardinality}</text>") if cardinality
|
|
40
|
+
draw_description(59)
|
|
41
|
+
draw_connection
|
|
42
|
+
draw_use
|
|
43
|
+
draw_g_end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def calculate_width
|
|
47
|
+
calc = Utils::WidthCalculator.new(MIN_WIDTH)
|
|
48
|
+
calc.new_width(15, namespace)
|
|
49
|
+
calc.new_width(15, cardinality)
|
|
50
|
+
calc.width
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def calculate_height
|
|
54
|
+
MAX_HEIGHT
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../symbol"
|
|
4
|
+
|
|
5
|
+
module Xsdvi
|
|
6
|
+
module SVG
|
|
7
|
+
module Symbols
|
|
8
|
+
# Symbol for XSD anyAttribute wildcard
|
|
9
|
+
class AnyAttribute < Symbol
|
|
10
|
+
attr_accessor :namespace, :process_contents
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
super
|
|
14
|
+
@namespace = nil
|
|
15
|
+
@process_contents = PC_STRICT
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def draw
|
|
19
|
+
process_description
|
|
20
|
+
draw_g_start
|
|
21
|
+
print("<rect class='shadow' x='3' y='3' width='#{width}' " \
|
|
22
|
+
"height='#{height}' rx='9'/>")
|
|
23
|
+
print("<rect class='boxanyattribute' x='0' y='0' width='#{width}' " \
|
|
24
|
+
"height='#{height}' rx='9'/>")
|
|
25
|
+
|
|
26
|
+
# Draw process contents boxes
|
|
27
|
+
pc_class = case process_contents
|
|
28
|
+
when PC_STRICT then "strict"
|
|
29
|
+
when PC_SKIP then "skip"
|
|
30
|
+
when PC_LAX then "lax"
|
|
31
|
+
else "strict"
|
|
32
|
+
end
|
|
33
|
+
print("<rect class='#{pc_class}' x='6' y='34' width='6' height='6'/>")
|
|
34
|
+
print("<rect class='#{pc_class}' x='16' y='34' width='6' height='6'/>")
|
|
35
|
+
print("<rect class='#{pc_class}' x='26' y='34' width='6' height='6'/>")
|
|
36
|
+
|
|
37
|
+
print("<text x='5' y='13'>#{namespace}</text>") if namespace
|
|
38
|
+
# Java only shows @ symbol, not the full text
|
|
39
|
+
print("<text class='strong' x='5' y='27'>@</text>")
|
|
40
|
+
draw_description(34)
|
|
41
|
+
draw_connection
|
|
42
|
+
draw_g_end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def calculate_width
|
|
46
|
+
calc = Utils::WidthCalculator.new(MIN_WIDTH)
|
|
47
|
+
# Java only calculates width based on namespace
|
|
48
|
+
calc.new_width(15, namespace)
|
|
49
|
+
calc.width
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def calculate_height
|
|
53
|
+
MAX_HEIGHT
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../symbol"
|
|
4
|
+
|
|
5
|
+
module Xsdvi
|
|
6
|
+
module SVG
|
|
7
|
+
module Symbols
|
|
8
|
+
# Symbol for XSD attributes
|
|
9
|
+
class Attribute < Symbol
|
|
10
|
+
attr_accessor :name, :namespace, :type, :required, :constraint
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
super
|
|
14
|
+
@name = nil
|
|
15
|
+
@namespace = nil
|
|
16
|
+
@type = nil
|
|
17
|
+
@required = false
|
|
18
|
+
@constraint = nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def draw
|
|
22
|
+
process_description
|
|
23
|
+
draw_g_start
|
|
24
|
+
print("<rect class='shadow' x='3' y='3' width='#{width}' " \
|
|
25
|
+
"height='#{height}' rx='9'/>")
|
|
26
|
+
if required
|
|
27
|
+
print("<rect class='boxattribute1' x='0' y='0' " \
|
|
28
|
+
"width='#{width}' height='#{height}' rx='9'")
|
|
29
|
+
else
|
|
30
|
+
print("<rect class='boxattribute2' x='0' y='0' " \
|
|
31
|
+
"width='#{width}' height='#{height}' rx='9'")
|
|
32
|
+
end
|
|
33
|
+
print("/>")
|
|
34
|
+
|
|
35
|
+
print("<text class='visible' x='5' y='13'>#{namespace}</text>") if namespace
|
|
36
|
+
print("<text class='strong' x='5' y='27'><tspan class='big'>@</tspan> #{name}</text>") if name
|
|
37
|
+
print("<text class='visible' x='5' y='41'>#{type}</text>") if type
|
|
38
|
+
|
|
39
|
+
properties = []
|
|
40
|
+
properties << constraint if constraint
|
|
41
|
+
print("<text x='5' y='59'>#{properties.join(', ')}</text>")
|
|
42
|
+
|
|
43
|
+
draw_description(59)
|
|
44
|
+
draw_connection
|
|
45
|
+
draw_g_end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def calculate_width
|
|
49
|
+
calc = Utils::WidthCalculator.new(MIN_WIDTH)
|
|
50
|
+
calc.new_width(15, name, 3)
|
|
51
|
+
calc.new_width(15, namespace)
|
|
52
|
+
calc.new_width(15, type)
|
|
53
|
+
calc.new_width(15, 13)
|
|
54
|
+
calc.new_width(15, constraint)
|
|
55
|
+
calc.width
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def calculate_height
|
|
59
|
+
MAX_HEIGHT
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../symbol"
|
|
4
|
+
|
|
5
|
+
module Xsdvi
|
|
6
|
+
module SVG
|
|
7
|
+
module Symbols
|
|
8
|
+
# Symbol for XSD choice compositor
|
|
9
|
+
class Choice < Symbol
|
|
10
|
+
attr_accessor :cardinality
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
super
|
|
14
|
+
@cardinality = nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def draw
|
|
18
|
+
process_description
|
|
19
|
+
draw_g_start
|
|
20
|
+
print("<rect class='boxcompositor' x='0' y='8' width='#{width}' " \
|
|
21
|
+
"height='#{height}' rx='9'/>")
|
|
22
|
+
print("<circle cx='#{(width / 2) + 12}' cy='14' r='2'/>")
|
|
23
|
+
print("<circle class='empty' cx='#{(width / 2) + 12}' cy='23' r='2'/>")
|
|
24
|
+
print("<circle class='empty' cx='#{(width / 2) + 12}' cy='32' r='2'/>")
|
|
25
|
+
print("<polyline points='#{(width / 2) - 4},23 #{(width / 2) + 4},23 " \
|
|
26
|
+
"#{(width / 2) + 4},14 #{(width / 2) + 10},14'/>")
|
|
27
|
+
print("<text x='5' y='52'>#{cardinality}</text>") if cardinality
|
|
28
|
+
draw_description(52)
|
|
29
|
+
draw_connection
|
|
30
|
+
draw_use
|
|
31
|
+
draw_g_end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def calculate_width
|
|
35
|
+
calc = Utils::WidthCalculator.new(MIN_WIDTH)
|
|
36
|
+
calc.new_width(15, cardinality)
|
|
37
|
+
calc.width
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def calculate_height
|
|
41
|
+
MID_HEIGHT
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../symbol"
|
|
4
|
+
|
|
5
|
+
module Xsdvi
|
|
6
|
+
module SVG
|
|
7
|
+
module Symbols
|
|
8
|
+
# Symbol for XSD elements
|
|
9
|
+
class Element < Symbol
|
|
10
|
+
attr_accessor :name, :namespace, :type, :cardinality, :nillable,
|
|
11
|
+
:abstract, :substitution, :optional
|
|
12
|
+
|
|
13
|
+
def initialize
|
|
14
|
+
super
|
|
15
|
+
@name = nil
|
|
16
|
+
@namespace = nil
|
|
17
|
+
@type = nil
|
|
18
|
+
@cardinality = nil
|
|
19
|
+
@optional = false
|
|
20
|
+
@nillable = false
|
|
21
|
+
@abstract = false
|
|
22
|
+
@substitution = nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def cardinality=(value)
|
|
26
|
+
@cardinality = value
|
|
27
|
+
@optional = true if value&.start_with?("0")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def draw
|
|
31
|
+
print("<a href=\"#\" onclick=\"window.parent.location.href = " \
|
|
32
|
+
"window.parent.location.href.split('#')[0] + " \
|
|
33
|
+
"'#element_#{name}'\">")
|
|
34
|
+
|
|
35
|
+
process_description
|
|
36
|
+
|
|
37
|
+
draw_g_start
|
|
38
|
+
print("<rect class='shadow' x='3' y='3' width='#{width}' " \
|
|
39
|
+
"height='#{height}'/>")
|
|
40
|
+
if optional
|
|
41
|
+
print("<rect class='boxelementoptional' x='0' y='0' " \
|
|
42
|
+
"width='#{width}' height='#{height}'/>")
|
|
43
|
+
else
|
|
44
|
+
print("<rect class='boxelement' x='0' y='0' width='#{width}' " \
|
|
45
|
+
"height='#{height}'/>")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Show namespace at y=13 (always shown in Java if present)
|
|
49
|
+
if namespace && !namespace.empty?
|
|
50
|
+
print("<text class='visible' x='5' y='13'>#{namespace}</text>")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Show name at y=27 (always shown in Java)
|
|
54
|
+
print("<text class='strong elementlink' x='5' y='27'>#{name}</text>") if name
|
|
55
|
+
|
|
56
|
+
# Show type at y=41 (always shown in Java if present)
|
|
57
|
+
print("<text class='visible' x='5' y='41'>#{type}</text>") if type && !type.empty?
|
|
58
|
+
|
|
59
|
+
# Properties at y=59
|
|
60
|
+
properties = []
|
|
61
|
+
properties << cardinality if cardinality
|
|
62
|
+
properties << "subst.: #{substitution}" if substitution
|
|
63
|
+
properties << "nillable: true" if nillable
|
|
64
|
+
properties << "abstract: true" if abstract
|
|
65
|
+
print("<text x='5' y='59'>#{properties.join(', ')}</text>")
|
|
66
|
+
|
|
67
|
+
draw_description(59)
|
|
68
|
+
draw_connection
|
|
69
|
+
draw_use
|
|
70
|
+
draw_g_end
|
|
71
|
+
print("</a>")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def calculate_width
|
|
75
|
+
calc = Utils::WidthCalculator.new(MIN_WIDTH)
|
|
76
|
+
calc.new_width(15, name, 3)
|
|
77
|
+
calc.new_width(15, namespace)
|
|
78
|
+
calc.new_width(15, type)
|
|
79
|
+
calc.new_width(15, cardinality)
|
|
80
|
+
calc.new_width(15, substitution ? 22 : 11)
|
|
81
|
+
calc.new_width(15, substitution, 8)
|
|
82
|
+
calc.width
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def calculate_height
|
|
86
|
+
MAX_HEIGHT
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../symbol"
|
|
4
|
+
|
|
5
|
+
module Xsdvi
|
|
6
|
+
module SVG
|
|
7
|
+
module Symbols
|
|
8
|
+
# Symbol for XSD field
|
|
9
|
+
class Field < Symbol
|
|
10
|
+
attr_accessor :xpath
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
super
|
|
14
|
+
@xpath = nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def draw
|
|
18
|
+
draw_g_start
|
|
19
|
+
print("<rect class='shadow' x='3' y='3' width='#{width}' " \
|
|
20
|
+
"height='#{height}' rx='9'/>")
|
|
21
|
+
print("<rect class='boxfield' x='0' y='0' width='#{width}' " \
|
|
22
|
+
"height='#{height}' rx='9'/>")
|
|
23
|
+
print("<text class='strong' x='5' y='13'>field</text>")
|
|
24
|
+
print("<text class='visible' x='5' y='27'>#{xpath}</text>") if xpath
|
|
25
|
+
draw_connection
|
|
26
|
+
draw_g_end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def calculate_width
|
|
30
|
+
calc = Utils::WidthCalculator.new(MIN_WIDTH)
|
|
31
|
+
calc.new_width(15, 5)
|
|
32
|
+
calc.new_width(15, xpath)
|
|
33
|
+
calc.width
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def calculate_height
|
|
37
|
+
MID_HEIGHT
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../symbol"
|
|
4
|
+
|
|
5
|
+
module Xsdvi
|
|
6
|
+
module SVG
|
|
7
|
+
module Symbols
|
|
8
|
+
# Symbol for XSD key identity constraint
|
|
9
|
+
class Key < Symbol
|
|
10
|
+
attr_accessor :name, :namespace
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
super
|
|
14
|
+
@name = nil
|
|
15
|
+
@namespace = nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def draw
|
|
19
|
+
process_description
|
|
20
|
+
draw_g_start
|
|
21
|
+
print("<rect class='shadow' x='3' y='3' width='#{width}' " \
|
|
22
|
+
"height='#{height}' rx='9'/>")
|
|
23
|
+
print("<rect class='boxkey' x='0' y='0' width='#{width}' " \
|
|
24
|
+
"height='#{height}' rx='9'/>")
|
|
25
|
+
print("<text class='visible' x='5' y='13'>#{namespace}</text>") if namespace
|
|
26
|
+
print("<text class='strong' x='5' y='27'>key: #{name}</text>") if name
|
|
27
|
+
draw_description(27)
|
|
28
|
+
draw_connection
|
|
29
|
+
draw_use
|
|
30
|
+
draw_g_end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def calculate_width
|
|
34
|
+
calc = Utils::WidthCalculator.new(MIN_WIDTH)
|
|
35
|
+
calc.new_width(15, name, 5)
|
|
36
|
+
calc.new_width(15, namespace)
|
|
37
|
+
calc.width
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def calculate_height
|
|
41
|
+
MID_HEIGHT
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|