3
# This file is part of Diamond.
5
# Diamond is free software: you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation, either version 3 of the License, or
8
# (at your option) any later version.
10
# Diamond is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with Diamond. If not, see <http://www.gnu.org/licenses/>.
18
from lxml import etree
26
def preprocess(schemafile):
27
p = etree.XMLParser(remove_comments=True)
28
ns = 'http://relaxng.org/ns/structure/1.0'
30
if 'http' in schemafile:
31
schemafile_handle = urllib2.urlopen(schemafile)
33
schemafile_handle = open(schemafile)
36
tree = etree.parse(schemafile_handle, p)
38
debug.deprint("Error: %s is not a valid Relax NG schema" % schemafile, 0)
44
includes = tree.xpath('/t:grammar//t:include', namespaces={'t': ns})
46
for include in includes:
47
include_parent = include.getparent()
48
include_index = list(include_parent).index(include)
52
filename = include.attrib["href"]
53
possible_files = [os.path.join(os.path.dirname(schemafile), filename), filename]
54
possible_files.append(os.path.join("/data/src/fluidity/fluidity_enkf_reduced_new/libspud/../share/spud", filename))
55
possible_files.append(os.path.join(os.path.dirname(__file__) + "/../../schema", filename))
57
for possible_file in possible_files:
59
if 'http' in possible_file:
60
file = urllib2.urlopen(possible_file)
62
file = open(possible_file)
65
debug.deprint("IOError when searching for included file " + filename, 1)
68
debug.deprint("Error: could not locate included file %s" % filename, 0)
69
debug.deprint("Path: %s" % possible_files)
72
# parse the included xml file and steal all the nodes
73
include_tree = etree.parse(file, p)
74
nodes_to_take = include_tree.xpath('/t:grammar/*', namespaces={'t': ns})
76
# here's where the magic happens:
77
for node in nodes_to_take:
78
include_parent.insert(include_index, copy.deepcopy(node))
80
# now delete the include:
81
include_parent.remove(include)
83
grammar_list = tree.xpath('/t:grammar', namespaces={'t': ns})
85
# If the .rnc didn't include a start = prefix, then no valid
86
# grammar tag will be present. Let the user know.
88
if len(grammar_list) == 0:
89
debug.deprint("Error: No grammar tag present in schema.", 0)
92
grammar = grammar_list[0]
95
define_nodes = tree.xpath('/t:grammar//t:define', namespaces={'t': ns})
98
# deal with combine="interleave"
101
# first, fetch all the plain definitions
102
for define in define_nodes:
103
if "combine" not in define.attrib:
104
name = define.attrib["name"]
105
defines[name] = define
107
# now look for interleaves with those
108
for define in define_nodes:
109
if "combine" in define.attrib and define.attrib["combine"] == "interleave":
110
name = define.attrib["name"]
111
if name not in defines:
112
defines[name] = define
114
matching_defn = defines[name]
116
matching_defn.append(copy.deepcopy(child))
119
# deal with combine="choice"
122
for define in define_nodes:
123
if "combine" in define.attrib and define.attrib["combine"] == "choice":
124
name = define.attrib["name"]
125
combine_names.append(name)
127
combine_names = list(set(combine_names))
128
for name in combine_names:
129
xpath = tree.xpath('/t:grammar//t:define[@name="%s"]' % name, namespaces={'t': ns})
132
choices = choices + list(node)
133
define = etree.Element("define")
134
define.attrib["name"] = name
135
choice = etree.Element("choice")
136
define.append(choice)
139
defines[name] = define
141
# delete all the define nodes from the xml
142
for define in define_nodes:
143
parent = define.getparent()
144
parent.remove(define)
146
# add the modified defines back to the grammar
147
for define in defines.values():
148
grammar.append(define)
150
return etree.tostring(tree, xml_declaration=True, encoding='utf-8', pretty_print=True)
152
if __name__ == "__main__":
154
schemafile = sys.argv[1]
155
newfile = schemafile.replace(".rng", ".pp.rng")
156
f = open(newfile, "w")
157
f.write(preprocess(schemafile))