duxml 0.7.2
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/bin/validate_xml +19 -0
- data/lib/duxml/doc/element.rb +157 -0
- data/lib/duxml/doc/lazy_ox.rb +153 -0
- data/lib/duxml/doc/node_set.rb +39 -0
- data/lib/duxml/doc.rb +26 -0
- data/lib/duxml/meta/grammar/pattern/attr_name_pattern.rb +36 -0
- data/lib/duxml/meta/grammar/pattern/attr_val_pattern.rb +36 -0
- data/lib/duxml/meta/grammar/pattern/child_pattern.rb +72 -0
- data/lib/duxml/meta/grammar/pattern/text_pattern.rb +30 -0
- data/lib/duxml/meta/grammar/pattern.rb +98 -0
- data/lib/duxml/meta/grammar/pattern_maker.rb +69 -0
- data/lib/duxml/meta/grammar/relax_ng/attrs_rule.rb +58 -0
- data/lib/duxml/meta/grammar/relax_ng/children_rule.rb +83 -0
- data/lib/duxml/meta/grammar/relax_ng/value_rule.rb +44 -0
- data/lib/duxml/meta/grammar/relax_ng.rb +40 -0
- data/lib/duxml/meta/grammar/rule/attrs_rule.rb +78 -0
- data/lib/duxml/meta/grammar/rule/children_rule.rb +137 -0
- data/lib/duxml/meta/grammar/rule/text_rule.rb +40 -0
- data/lib/duxml/meta/grammar/rule/value_rule.rb +111 -0
- data/lib/duxml/meta/grammar/rule.rb +59 -0
- data/lib/duxml/meta/grammar/spreadsheet.rb +35 -0
- data/lib/duxml/meta/grammar.rb +134 -0
- data/lib/duxml/meta/history/add.rb +36 -0
- data/lib/duxml/meta/history/change.rb +71 -0
- data/lib/duxml/meta/history/change_attr.rb +34 -0
- data/lib/duxml/meta/history/change_text.rb +33 -0
- data/lib/duxml/meta/history/error.rb +25 -0
- data/lib/duxml/meta/history/new_attr.rb +33 -0
- data/lib/duxml/meta/history/new_text.rb +37 -0
- data/lib/duxml/meta/history/qualify_error.rb +22 -0
- data/lib/duxml/meta/history/remove.rb +28 -0
- data/lib/duxml/meta/history/undo.rb +24 -0
- data/lib/duxml/meta/history/validate_error.rb +21 -0
- data/lib/duxml/meta/history.rb +88 -0
- data/lib/duxml/meta.rb +51 -0
- data/lib/duxml/reportable.rb +27 -0
- data/lib/duxml/ruby_ext/fixnum.rb +56 -0
- data/lib/duxml/ruby_ext/module.rb +12 -0
- data/lib/duxml/ruby_ext/object.rb +14 -0
- data/lib/duxml/ruby_ext/regexp.rb +20 -0
- data/lib/duxml/ruby_ext/string.rb +29 -0
- data/lib/duxml/saxer.rb +71 -0
- data/lib/duxml.rb +97 -0
- data/xml/dita_grammar.xml +2133 -0
- metadata +117 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/history/add')
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/history/remove')
|
5
|
+
require File.expand_path(File.dirname(__FILE__) + '/history/validate_error')
|
6
|
+
require File.expand_path(File.dirname(__FILE__) + '/history/qualify_error')
|
7
|
+
require File.expand_path(File.dirname(__FILE__) + '/history/new_attr')
|
8
|
+
require File.expand_path(File.dirname(__FILE__) + '/history/change_attr')
|
9
|
+
require File.expand_path(File.dirname(__FILE__) + '/history/new_text')
|
10
|
+
require File.expand_path(File.dirname(__FILE__) + '/history/change_text')
|
11
|
+
require File.expand_path(File.dirname(__FILE__) + '/history/undo')
|
12
|
+
require File.expand_path(File.dirname(__FILE__) + '/../doc')
|
13
|
+
require 'forwardable'
|
14
|
+
|
15
|
+
module Duxml
|
16
|
+
# monitors XML Elements for changes and GrammarClass for errors, recording them and saving to Meta file
|
17
|
+
module History
|
18
|
+
include Duxml
|
19
|
+
include Reportable
|
20
|
+
end
|
21
|
+
|
22
|
+
# as an object, HistoryClass holds events latest first, earliest last
|
23
|
+
# it also has delegators that allow the use of Array-style notation e.g. '[]' and #each to search the history.
|
24
|
+
class HistoryClass
|
25
|
+
include History
|
26
|
+
extend Forwardable
|
27
|
+
|
28
|
+
def_delegators :@nodes, :[], :each
|
29
|
+
|
30
|
+
# @param harsh_or_kind [Boolean] by default harsh i.e. true so that if this History detects an error it will raise an Exception; otherwise not
|
31
|
+
def initialize(harsh_or_kind = true)
|
32
|
+
@nodes = []
|
33
|
+
@strict = harsh_or_kind
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :nodes
|
37
|
+
alias_method :events, :nodes
|
38
|
+
end
|
39
|
+
|
40
|
+
module History
|
41
|
+
# used when creating a new metadata file for a static XML file
|
42
|
+
#
|
43
|
+
# @return [Element] XML element for a new <duxml:history> node
|
44
|
+
def self.xml
|
45
|
+
Element.new(name.nmtokenize).extend self
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [Boolean] toggles (true by default) whether History will raise exception or tolerate qualify errors
|
49
|
+
def strict?(harsh_or_kind=nil)
|
50
|
+
@strict = harsh_or_kind.nil? ? @strict : harsh_or_kind
|
51
|
+
@strict
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [ChangeClass, ErrorClass] the latest event
|
55
|
+
def latest
|
56
|
+
events[0]
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [GrammarClass] grammar that is observing this history's events
|
60
|
+
def grammar
|
61
|
+
@observer_peers.first.first if @observer_peers and @observer_peers.any? and @observer_peers.first.any?
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [String] shortened self description for debugging
|
65
|
+
def inspect
|
66
|
+
"#<#{self.class.to_s} #{object_id}: @events=#{nodes.size}>"
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [String] returns entire history, calling #description on each event in chronological order
|
70
|
+
def description
|
71
|
+
"history follows: \n" +
|
72
|
+
events.reverse.collect do |change_or_error|
|
73
|
+
change_or_error.description
|
74
|
+
end.join("\n")
|
75
|
+
end
|
76
|
+
|
77
|
+
# @param type [Symbol] category i.e. class symbol of changes/errors reported
|
78
|
+
# @param *args [*several_variants] information needed to accurately log the event; varies by change/error class
|
79
|
+
def update(type, *args)
|
80
|
+
change_class = Duxml::const_get "#{type.to_s}Class".to_sym
|
81
|
+
change_comp = change_class.new *args
|
82
|
+
@nodes.unshift change_comp
|
83
|
+
changed
|
84
|
+
notify_observers(change_comp) unless change_comp.respond_to?(:error?)
|
85
|
+
raise(Exception, change_comp.description) if strict? && type == :QualifyError
|
86
|
+
end
|
87
|
+
end # module History
|
88
|
+
end # module Duxml
|
data/lib/duxml/meta.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/meta/grammar')
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/meta/history')
|
5
|
+
require File.expand_path(File.dirname(__FILE__) + '/saxer')
|
6
|
+
|
7
|
+
module Duxml
|
8
|
+
module Meta
|
9
|
+
|
10
|
+
FILE_EXT = '.duxml'
|
11
|
+
end
|
12
|
+
|
13
|
+
# all XML files ready by Duxml have a metadata file generated with a modified, matching file name
|
14
|
+
# @see #Meta.meta_path
|
15
|
+
class MetaClass
|
16
|
+
include Meta
|
17
|
+
|
18
|
+
# @param grammar_path [String] optional path of grammar file which can be a spreadsheet or Duxml::Grammar file
|
19
|
+
def initialize(grammar_path=nil)
|
20
|
+
@history = HistoryClass.new
|
21
|
+
self.grammar = grammar_path ? Grammar.import(grammar_path) : GrammarClass.new
|
22
|
+
@grammar_path = grammar_path
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :history, :grammar
|
26
|
+
end
|
27
|
+
|
28
|
+
module Meta
|
29
|
+
# @return [Doc] metadata document
|
30
|
+
def self.xml
|
31
|
+
d = Doc.new << (Element.new(name.nmtokenize) << Grammar.xml << History.xml)
|
32
|
+
d.root.grammar[:ref] = @grammar_path if @grammar_path
|
33
|
+
d
|
34
|
+
end
|
35
|
+
|
36
|
+
# @param path [String] path of XML-content file
|
37
|
+
# @return [String] full path of metadata file based on content file's name e.g.
|
38
|
+
# 'design.xml' => '.design.xml.duxml'
|
39
|
+
def self.meta_path(path)
|
40
|
+
dir = File.dirname(path)
|
41
|
+
"#{dir}/.#{File.basename(path)}#{FILE_EXT}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def grammar=(g)
|
45
|
+
@grammar = g.is_a?(GrammarClass) ? g : Grammar.import(g)
|
46
|
+
history.delete_observers if history.respond_to?(:delete_observers)
|
47
|
+
history.add_observer(grammar, :qualify)
|
48
|
+
grammar.add_observer history
|
49
|
+
end
|
50
|
+
end # module Meta
|
51
|
+
end # module Duxml
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
+
|
3
|
+
require 'observer'
|
4
|
+
|
5
|
+
module Reportable
|
6
|
+
include Observable
|
7
|
+
|
8
|
+
# @param obs [Object] observer to add to this Element as well as its NodeSet
|
9
|
+
def add_observer(obs, sym=nil)
|
10
|
+
super(obs, sym || :update)
|
11
|
+
nodes.add_observer(obs) if self.respond_to?(:nodes) and nodes.respond_to?(:add_observer)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
# all public methods that alter XML must call #report in the full scope of that public method
|
17
|
+
# in order to correctly acquire name of method that called #report
|
18
|
+
#
|
19
|
+
# @param *args [*several_variants]
|
20
|
+
def report(*args)
|
21
|
+
return nil if @observer_peers.nil?
|
22
|
+
changed
|
23
|
+
new_args = [args.first, self]
|
24
|
+
args[1..-1].each do |a| new_args << a end if args.size > 1
|
25
|
+
notify_observers(*new_args)
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
+
|
3
|
+
class Fixnum
|
4
|
+
NUM_NAMES = %w(zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty thirty forty fifty sixty seventy eighty ninety)
|
5
|
+
ORDINAL_SUFFIXES = %w(th st nd rd th)
|
6
|
+
ORDINAL_NAMES = %w(zeroth first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelfth)
|
7
|
+
|
8
|
+
# @return [String] short string ordinal e.g. 3.ordinal =? 'third'
|
9
|
+
def ordinal
|
10
|
+
self.to_s + suffix
|
11
|
+
end
|
12
|
+
|
13
|
+
def suffix
|
14
|
+
if self%100 < 4 or self%100 > 20
|
15
|
+
ORDINAL_SUFFIXES[self%10]
|
16
|
+
else
|
17
|
+
ORDINAL_SUFFIXES.first
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [String] full name of number e.g. 200058.to_word => 'two-hundred thousand and fifty-eight' for any Fixnum less than a billion
|
22
|
+
def to_word
|
23
|
+
case
|
24
|
+
when self < 21 then NUM_NAMES[self]
|
25
|
+
when self < 100
|
26
|
+
ones = self%10
|
27
|
+
ones_str = ones.zero? ? '' : "-#{ones.to_word}"
|
28
|
+
NUM_NAMES[self/10+18]+ones_str
|
29
|
+
when self < 1000
|
30
|
+
tens = self%100
|
31
|
+
"#{NUM_NAMES[self/100]} hundred #{'and '+(tens).to_word unless tens.zero?}"
|
32
|
+
when self < 1000000
|
33
|
+
remainder = self%1000 < 100 ? "and #{(self%1000).to_word}" : (self%1000).to_word
|
34
|
+
"#{(self/1000).to_word} thousand #{remainder}"
|
35
|
+
when self < 1000000000
|
36
|
+
"#{(self/1000000).to_word} million #{(self%1000000).to_word}"
|
37
|
+
else raise Exception, 'method only supports names for numbers less than 1000000000 i.e. <= 999,999,999'
|
38
|
+
end.strip.gsub(' and zero', '')
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [String] full name of ordinal number e.g. 4281.ordinal_name => 'four thousand and two-hundred eighty-first'
|
42
|
+
def ordinal_name
|
43
|
+
ones = self%10
|
44
|
+
tens = self%100
|
45
|
+
case
|
46
|
+
when tens.zero? then self.to_word+ORDINAL_SUFFIXES.first
|
47
|
+
when ones.zero? && tens > 10 then self.to_word[-3..-1] + 'tieth'
|
48
|
+
when ones.zero? && tens == 10 then self.to_word+ORDINAL_SUFFIXES.first
|
49
|
+
when tens < 13 then "#{(self-tens).to_word} and #{ORDINAL_NAMES[tens]}"
|
50
|
+
when tens < 20 && tens > 12
|
51
|
+
"#{(self-tens).to_word} and #{NUM_NAMES[tens]}#{ORDINAL_SUFFIXES.first}"
|
52
|
+
when tens-ones != 0 then "#{(self-ones).to_word}-#{ORDINAL_NAMES[ones]}"
|
53
|
+
else "#{(self-ones).to_word} and #{ORDINAL_NAMES[ones]}"
|
54
|
+
end.strip.gsub('zero and ', '').gsub('zero', '')
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/string')
|
4
|
+
|
5
|
+
class Object
|
6
|
+
def simple_name
|
7
|
+
self.class.to_s.split('::').last
|
8
|
+
end
|
9
|
+
|
10
|
+
def simple_module
|
11
|
+
a = self.class.to_s.split('::')
|
12
|
+
a.size > 1 ? a[-2] : 'Module'
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
+
|
3
|
+
class Regexp
|
4
|
+
class << self
|
5
|
+
# @return [Regexp] C identifier e.g. ident_ifier0, excluding 'true' and 'false'
|
6
|
+
def identifier
|
7
|
+
/(?:(?!true|false))\b([a-zA-Z_][a-zA-Z0-9_]*)\b/
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return [Regexp] XML NMTOKEN e.g xml:attribute, also-valid, CDATA
|
11
|
+
def nmtoken
|
12
|
+
/(?!\s)([a-zA-Z0-9_\-.:]*)(?!\s)/
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Regexp] Ruby constant e.g. Constant, CONSTANT
|
16
|
+
def constant
|
17
|
+
/\b([A-Z][a-zA-Z0-9_]*)\b/
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/regexp')
|
3
|
+
|
4
|
+
class String
|
5
|
+
# @return [String] converts string into Ruby constant. self must be String with no whitespaces and match Regexp.nmtoken
|
6
|
+
# 'foo-bar'.constantize => 'Foo_bar'
|
7
|
+
# 'foo_bar'.constantize => 'FooBar'
|
8
|
+
def constantize
|
9
|
+
return self if Regexp.constant.match(self)
|
10
|
+
raise Exception unless Regexp.nmtoken.match(self)
|
11
|
+
s = split('_').collect do |word| word.capitalize unless word == '_' end.join.gsub('-', '_')
|
12
|
+
raise Exception unless s.match(Regexp.constant)
|
13
|
+
s
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [String] does reverse of #constantize e.g.
|
17
|
+
# 'Foo_b'.nmtokenize => 'foo-bar'
|
18
|
+
# 'FooBar'.nmtokenize => 'foo_bar'
|
19
|
+
def nmtokenize
|
20
|
+
split('::').collect do |word|
|
21
|
+
word.gsub(/(?!^)[A-Z_]/) do |match|
|
22
|
+
case match
|
23
|
+
when '_' then '-'
|
24
|
+
else "_#{match.downcase}"
|
25
|
+
end
|
26
|
+
end.downcase
|
27
|
+
end.join(':')
|
28
|
+
end
|
29
|
+
end # class String
|
data/lib/duxml/saxer.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/doc')
|
4
|
+
|
5
|
+
module Duxml
|
6
|
+
module Saxer
|
7
|
+
@io
|
8
|
+
|
9
|
+
attr_accessor :io
|
10
|
+
# @param path [String] path of file to parse
|
11
|
+
# @return [Doc] finished document with each Element's line and column info added
|
12
|
+
def sax(path, obs=nil)
|
13
|
+
io = File.open path
|
14
|
+
saxer = DocuLiner.new(Duxml::Doc.new, obs)
|
15
|
+
Ox.sax_parse(saxer, io, {convert_special: true, symbolize: false})
|
16
|
+
doc = saxer.cursor
|
17
|
+
doc.add_observer obs if obs
|
18
|
+
doc
|
19
|
+
end
|
20
|
+
|
21
|
+
class DocuLiner < ::Ox::Sax
|
22
|
+
# @param doc [Ox::Document] document that is being constructed as XML is parsed
|
23
|
+
# @param _observer [Object] object that will observe this document's content
|
24
|
+
def initialize(doc, _observer)
|
25
|
+
@cursor_stack = [doc]
|
26
|
+
@line = 0
|
27
|
+
@column = 0
|
28
|
+
@observer = _observer
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :line, :column, :observer
|
32
|
+
|
33
|
+
def cursor
|
34
|
+
cursor_stack.last
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_accessor :cursor_stack
|
38
|
+
|
39
|
+
def start_element(name)
|
40
|
+
cursor << Duxml::Element.new(name, line, column)
|
41
|
+
cursor_stack << cursor.nodes.last
|
42
|
+
end
|
43
|
+
|
44
|
+
def attr(name, val)
|
45
|
+
cursor[name] = val
|
46
|
+
end
|
47
|
+
|
48
|
+
def text(str)
|
49
|
+
cursor << str
|
50
|
+
end
|
51
|
+
|
52
|
+
def end_element(name)
|
53
|
+
cursor.add_observer(observer) if observer
|
54
|
+
@cursor_stack.pop
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def doc
|
60
|
+
cursor_stack.first
|
61
|
+
end
|
62
|
+
|
63
|
+
def location_key
|
64
|
+
@alocation.inject do |a, index|
|
65
|
+
a ||= ""
|
66
|
+
a << index.to_s
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end # class DocuLiner < ::Ox::Sax
|
70
|
+
end # module Saxer
|
71
|
+
end # module Duxml
|
data/lib/duxml.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# Copyright (c) 2016 Freescale Semiconductor Inc.
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/duxml/saxer')
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/duxml/meta')
|
5
|
+
|
6
|
+
module Duxml
|
7
|
+
DITA_GRAMMAR = File.expand_path(File.dirname(__FILE__) + '/../xml/dita_grammar.xml')
|
8
|
+
include Saxer
|
9
|
+
include Meta
|
10
|
+
|
11
|
+
# path to XML file
|
12
|
+
@file
|
13
|
+
# current document
|
14
|
+
@doc
|
15
|
+
# meta data document
|
16
|
+
@meta
|
17
|
+
|
18
|
+
attr_reader :meta, :file, :doc
|
19
|
+
|
20
|
+
# @param file [String, Doc] loads or creates given file or document and finds or creates corresponding metadata file e.g. '.xml_file.duxml'
|
21
|
+
# @param grammar_path [nil, String, Duxml::Grammar] optional - provide an external grammar file or object
|
22
|
+
# @return [Duxml::Meta] combined Object tree from metadata root (metadata and content's XML documents are kept separate)
|
23
|
+
def load(_file, grammar_path=nil)
|
24
|
+
if _file.is_a?(String) and File.exists?(_file)
|
25
|
+
@file = _file
|
26
|
+
else
|
27
|
+
@file = "#{(_file.respond_to?(:name) ? _file.name : _file.class.to_s) + _file.object_id.to_s}"
|
28
|
+
File.write file, ''
|
29
|
+
end
|
30
|
+
|
31
|
+
set_metadata!(grammar_path)
|
32
|
+
set_doc!
|
33
|
+
end # def load
|
34
|
+
|
35
|
+
# @param file [String] creates new XML file at given path
|
36
|
+
# @param content [Doc, Element] XML content with which to initialize new file
|
37
|
+
def create(file, content=nil)
|
38
|
+
File.write(file, content.to_s)
|
39
|
+
@doc = content.is_a?(Doc) ? content : Doc.new
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param file [String] saves current content XML to given file path (Duxml@file by default)
|
43
|
+
def save(file)
|
44
|
+
meta_path = Meta.meta_path(file)
|
45
|
+
unless File.exists?(meta_path)
|
46
|
+
File.new meta_path, 'w+'
|
47
|
+
File.write(meta_path, Meta.xml)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# @param file [String] output file path for logging human-readable validation error messages
|
52
|
+
def log(file)
|
53
|
+
File.write(file, meta.history.description)
|
54
|
+
end
|
55
|
+
|
56
|
+
# @param *Args [*several_variants] @see #load
|
57
|
+
# @return [Boolean] whether file passed validation
|
58
|
+
def validate(*args)
|
59
|
+
load(*args) unless args.empty?
|
60
|
+
raise Exception, "grammar not defined!" unless meta.grammar.defined?
|
61
|
+
raise Exception, "document not loaded!" unless doc.root
|
62
|
+
results = []
|
63
|
+
doc.root.traverse do |n| results << meta.grammar.validate(n) unless n.is_a?(String) end
|
64
|
+
!results.any? do |r| !r end
|
65
|
+
end # def validate
|
66
|
+
|
67
|
+
# @return [Nokogiri::XML::RelaxNG] current metadata's grammar as a relaxng file
|
68
|
+
def relaxng
|
69
|
+
#meta.grammar.relaxng
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# @return [Doc] @doc is set to either file given by user or new Doc
|
75
|
+
def set_doc!
|
76
|
+
@doc ||= if file.nil?
|
77
|
+
f = Doc.new
|
78
|
+
f.add_observer meta.history
|
79
|
+
f
|
80
|
+
else
|
81
|
+
f = File.open file
|
82
|
+
sax(f, meta.history)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# @return [MetaClass] @meta is set to either file extrapolated from path of XML-content file or new MetaClass
|
87
|
+
def set_metadata!(grammar_path=nil)
|
88
|
+
meta_path = Meta.meta_path(file)
|
89
|
+
if file and File.exists?(meta_path)
|
90
|
+
@meta = sax(File.open(meta_path)).root
|
91
|
+
meta.grammar=grammar_path unless grammar_path.nil? or meta.grammar.defined?
|
92
|
+
else
|
93
|
+
@meta = MetaClass.new(grammar_path)
|
94
|
+
end
|
95
|
+
meta
|
96
|
+
end
|
97
|
+
end # module Duxml
|