schematronium 0.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 520909cf6a2ba7b59423fc3894583ec0da94640e
4
+ data.tar.gz: 2779f180b43c93fd220b9ef5f55a45da9bd2235c
5
+ SHA512:
6
+ metadata.gz: cb4d0dfb69c613e2b39304bcdbc839b8c4be8ad0f29de60f6d4c43815ea2f040a9ebfe2751f12de1c1adedbbea573e3fee8c1bb2ab6ace5fcd0adbde27750583
7
+ data.tar.gz: ba936fda68f7ac25513012ad22a11420dc3a9ccb99d7bde0491cb62bfd80ca472993072f249ed44e299147e019f3010942bdb136bb19c0adbbde036ebef5e0c9
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ Gemfile.lock
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ jruby-1.7
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - "jruby-19mode"
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # A sample Gemfile
2
+ source "https://rubygems.org"
3
+
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # Schematronium
2
+
3
+ Schematronium is a gem providing:
4
+
5
+ 1. A single-object, single-function API for compiling a [schematron](http://www.schematron.com/) script, and running it over an XML file, returning a [Nokogiri](Nokogiri.org) [NodeSet](http://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/NodeSet) of the resulting `failed-assert`s and `successful-report`s.
6
+ 2. A script ([schematronium](bin/schematronium)) to run a schematron over one or many XML files and return aggregate date in a TBD format. Mostly meant as an example of something you could to with it.
7
+
8
+ The goals of Schematronium are very similar to [schematron-wrapper](https://github.com/Agilefreaks/schematron-wrapper). The primary difference is that, where schematron-wrapper runs the saxon jar via backticks per file, Schematronium uses the jRuby-only [saxon-xslt](https://github.com/fidothe/saxon-xslt) library to compile and run the schematron. This has the upshot of not incurring the penalty of JDK initialization per file, which tends to be a substantial cost savings over even a small number of files.
9
+
10
+ ## Requirements
11
+
12
+ * jRuby - Schematron is tested with jRuby 9000, but may be suitable for use with earlier jRubies.
13
+ * JDK requirement is essentially whatever your chosen jRuby demands.
14
+ * [saxon-xslt](https://github.com/fidothe/saxon-xslt)
15
+ * [Nokogiri](Nokogiri.org)
16
+
17
+ ## API
18
+
19
+ API docs are hosted [here](http://www.rubydoc.info/github/harvard-library/schematronium/master).
20
+
21
+ The API for Schematronium is very, very minimal.
22
+
23
+ ```Ruby
24
+ checker = Schematronium.new("schematron_filename.sch")
25
+
26
+ failed_assert_nodeset = checker.check(filename_or_IO_object_supporting_read)
27
+ ```
28
+
29
+ Processing the NodeSet into the report or output you desire is left as an exercise to the consumer.
30
+
31
+ ## Known issues
32
+
33
+ ### Redundant parsing
34
+
35
+ Right now, the Saxon::XML::Document object returned by saxon-xslt is pretty opaque. In order to get a reasonable API on the returned results, Schematronium is just rendering the returned doc to a string, then re-parsing with Nokogiri and using its API to pull out the `failed-assert`s and `successful-report`s.
36
+
37
+ It's possible that someone who knew more about XDMDocument (and Java XML-handling in general) than your humble author might be able to dispense with the use of Nokogiri, and thus reduce dependencies and (probably) memory/execution time.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << File.join(File.dirname(__FILE__), 'lib')
6
+ t.test_files = FileList['test/test*.rb']
7
+ t.verbose = true
8
+ end
9
+
10
+ task :default => :test
data/bin/schematronium ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env jruby
2
+ $LOAD_PATH.unshift(File.expand_path('./lib'), File.dirname(__FILE__))
3
+ require 'schematronium'
4
+
5
+ raise "Not enough arguments" if ARGV.length < 2
6
+
7
+ Saxon::Processor.default.config[:line_numbering] = true
8
+
9
+ stron = Schematronium.new(ARGV.shift)
10
+
11
+ @fnames = []
12
+
13
+ if ARGV.empty?
14
+ @fnames = @fnames + Dir[File.join('.', "*.xml")]
15
+ else
16
+ ARGV.each do |arg|
17
+ # Because absolute_path doesn't work right? Investigate
18
+ arg = arg.sub(/~/, Dir.home)
19
+
20
+ @fnames += case File.absolute_path(arg)
21
+ when File.method(:directory?).to_proc
22
+ Dir[File.join(File.absolute_path(arg), "*.xml")]
23
+ when File.method(:file?).to_proc
24
+ [File.absolute_path(arg)]
25
+ else
26
+ []
27
+ end
28
+ end
29
+ end
30
+
31
+ puts '<?xml version="1.0" encoding="UTF-8"?><files>'
32
+ @fnames.each do |f|
33
+ $stderr.write "Processing '#{f}'..."
34
+ s_xml = Saxon.XML(File.open(f))
35
+ xml = stron.check(s_xml)
36
+ xml.remove_namespaces!
37
+
38
+ xml = xml.xpath("//*[self::failed-assert or self::successful-report]")
39
+ xml.each do |el|
40
+ el["line-number"] = s_xml.xpath(el.attr("location")).get_line_number
41
+ end
42
+ output = Nokogiri::XML::DocumentFragment.new(Nokogiri::XML::Document.new)
43
+
44
+ file = output.add_child("<file id='#{f}' total_errors='#{xml.count}'/>").first
45
+ counts = xml.group_by {|el| el.children.map(&:text).join.strip.gsub(/\s+/, ' ')}.reduce({}) {|res, (k,v)| res[k] = v.count; res}
46
+ err_count = file.add_child("<error_counts />").first
47
+ counts.each do |k,v|
48
+ err_count.add_child("<message count='#{v}'>#{k}</message>")
49
+ end
50
+ errs = file.add_child("<errors />").first
51
+ errs.children = xml
52
+
53
+ puts output
54
+
55
+ $stderr.write " Finished\n"
56
+ end
57
+
58
+ puts '</files>'
@@ -0,0 +1,75 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ Stylesheet for extracting Schematron information from a RELAX-NG schema.
4
+ Based on the stylesheet for extracting Schematron information from W3C XML Schema.
5
+ Created by Eddie Robertsson 2002/06/01
6
+ Update for ISO Schematron using XSLT2 Rick Jelliffe 2010/04/14
7
+ -->
8
+ <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
9
+ xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:rng="http://relaxng.org/ns/structure/1.0">
10
+ <!-- Set the output to be XML with an XML declaration and use indentation -->
11
+ <xsl:output method="xml" omit-xml-declaration="no" indent="yes" standalone="yes"/>
12
+ <!-- -->
13
+ <!-- match schema and call recursive template to extract included schemas -->
14
+ <!-- -->
15
+ <xsl:template match="/rng:grammar | /rng:element">
16
+ <!-- call the schema definition template ... -->
17
+ <xsl:call-template name="gatherSchema">
18
+ <!-- ... with current node as the $schemas parameter ... -->
19
+ <xsl:with-param name="schemas" select="."/>
20
+ <!-- ... and any includes in the $include parameter -->
21
+ <xsl:with-param name="includes" select="document(/rng:grammar/rng:include/@href
22
+ | //rng:externalRef/@href)"/>
23
+ </xsl:call-template>
24
+ </xsl:template>
25
+ <!-- -->
26
+ <!-- gather all included schemas into a single parameter variable -->
27
+ <!-- -->
28
+ <xsl:template name="gatherSchema">
29
+ <xsl:param name="schemas"/>
30
+ <xsl:param name="includes"/>
31
+ <xsl:choose>
32
+ <xsl:when test="count($schemas) &lt; count($schemas | $includes)">
33
+ <!-- when $includes includes something new, recurse ... -->
34
+ <xsl:call-template name="gatherSchema">
35
+ <!-- ... with current $includes added to the $schemas parameter ... -->
36
+ <xsl:with-param name="schemas" select="$schemas | $includes"/>
37
+ <!-- ... and any *new* includes in the $include parameter -->
38
+ <xsl:with-param name="includes" select="document($includes/rng:grammar/rng:include/@href
39
+ | $includes//rng:externalRef/@href)"/>
40
+ </xsl:call-template>
41
+ </xsl:when>
42
+ <xsl:otherwise>
43
+ <!-- we have the complete set of included schemas, so now let's output the embedded schematron -->
44
+ <xsl:call-template name="output">
45
+ <xsl:with-param name="schemas" select="$schemas"/>
46
+ </xsl:call-template>
47
+ </xsl:otherwise>
48
+ </xsl:choose>
49
+ </xsl:template>
50
+ <!-- -->
51
+ <!-- output the schematron information -->
52
+ <!-- -->
53
+ <xsl:template name="output">
54
+ <xsl:param name="schemas"/>
55
+ <!-- -->
56
+ <sch:schema queryBinding="xslt2" >
57
+ <!-- get header-type elements - eg title and especially ns -->
58
+ <!-- title (just one) -->
59
+ <xsl:copy-of select="$schemas//sch:title[1]"/>
60
+ <!-- get remaining schematron schema children -->
61
+ <!-- get non-blank namespace elements, dropping duplicates -->
62
+ <xsl:for-each select="$schemas//sch:ns">
63
+ <xsl:if test="generate-id(.) = generate-id($schemas//sch:ns[@prefix = current()/@prefix][1])">
64
+ <xsl:copy-of select="."/>
65
+ </xsl:if>
66
+ </xsl:for-each>
67
+ <xsl:copy-of select="$schemas//sch:phase"/>
68
+ <xsl:copy-of select="$schemas//sch:pattern"/>
69
+ <sch:diagnostics>
70
+ <xsl:copy-of select="$schemas//sch:diagnostics/*"/>
71
+ </sch:diagnostics>
72
+ </sch:schema>
73
+ </xsl:template>
74
+ <!-- -->
75
+ </xsl:transform>
@@ -0,0 +1,77 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ based on an original transform by Eddie Robertsson
4
+ 2001/04/21 fn: added support for included schemas
5
+ 2001/06/27 er: changed XMl Schema prefix from xsd: to xs: and changed to the Rec namespace
6
+ 2010/04/14 rj: Update for ISO Schematron using xslt2
7
+ -->
8
+ <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
9
+ xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:xs="http://www.w3.org/2001/XMLSchema">
10
+ <!-- Set the output to be XML with an XML declaration and use indentation -->
11
+ <xsl:output method="xml" omit-xml-declaration="no" indent="yes" standalone="yes"/>
12
+ <!-- -->
13
+ <!-- match schema and call recursive template to extract included schemas -->
14
+ <!-- -->
15
+ <xsl:template match="xs:schema">
16
+ <!-- call the schema definition template ... -->
17
+ <xsl:call-template name="gatherSchema">
18
+ <!-- ... with current current root as the $schemas parameter ... -->
19
+ <xsl:with-param name="schemas" select="/"/>
20
+ <!-- ... and any includes in the $include parameter -->
21
+ <xsl:with-param name="includes"
22
+ select="document(/xs:schema/xs:*[self::xs:include or self::xs:import or self::xs:redefine]/@schemaLocation)"/>
23
+ </xsl:call-template>
24
+ </xsl:template>
25
+ <!-- -->
26
+ <!-- gather all included schemas into a single parameter variable -->
27
+ <!-- -->
28
+ <xsl:template name="gatherSchema">
29
+ <xsl:param name="schemas"/>
30
+ <xsl:param name="includes"/>
31
+ <xsl:choose>
32
+ <xsl:when test="count($schemas) &lt; count($schemas | $includes)">
33
+ <!-- when $includes includes something new, recurse ... -->
34
+ <xsl:call-template name="gatherSchema">
35
+ <!-- ... with current $includes added to the $schemas parameter ... -->
36
+ <xsl:with-param name="schemas" select="$schemas | $includes"/>
37
+ <!-- ... and any *new* includes in the $include parameter -->
38
+ <xsl:with-param name="includes"
39
+ select="document($includes/xs:schema/xs:*[self::xs:include or self::xs:import or self::xs:redefine]/@schemaLocation)"/>
40
+ </xsl:call-template>
41
+ </xsl:when>
42
+ <xsl:otherwise>
43
+ <!-- we have the complete set of included schemas,
44
+ so now let's output the embedded schematron -->
45
+ <xsl:call-template name="output">
46
+ <xsl:with-param name="schemas" select="$schemas"/>
47
+ </xsl:call-template>
48
+ </xsl:otherwise>
49
+ </xsl:choose>
50
+ </xsl:template>
51
+ <!-- -->
52
+ <!-- output the schematron information -->
53
+ <!-- -->
54
+ <xsl:template name="output">
55
+ <xsl:param name="schemas"/>
56
+ <!-- -->
57
+ <sch:schema queryBinding="xslt2">
58
+ <!-- get header-type elements - eg title and especially ns -->
59
+ <!-- title (just one) -->
60
+ <xsl:copy-of select="$schemas//xs:appinfo/sch:title[1]"/>
61
+ <!-- get remaining schematron schema children -->
62
+ <!-- get non-blank namespace elements, dropping duplicates -->
63
+ <xsl:for-each select="$schemas//xs:appinfo/sch:ns">
64
+ <xsl:if test="generate-id(.) =
65
+ generate-id($schemas//xs:appinfo/sch:ns[@prefix = current()/@prefix][1])">
66
+ <xsl:copy-of select="."/>
67
+ </xsl:if>
68
+ </xsl:for-each>
69
+ <xsl:copy-of select="$schemas//xs:appinfo/sch:phase"/>
70
+ <xsl:copy-of select="$schemas//xs:appinfo/sch:pattern"/>
71
+ <sch:diagnostics>
72
+ <xsl:copy-of select="$schemas//xs:appinfo/sch:diagnostics/*"/>
73
+ </sch:diagnostics>
74
+ </sch:schema>
75
+ </xsl:template>
76
+ <!-- -->
77
+ </xsl:transform>
@@ -0,0 +1,297 @@
1
+ <?xml version="1.0" encoding="UTF-8"?><?xar XSLT?>
2
+
3
+ <!--
4
+ OVERVIEW - iso_abstract_expand.xsl
5
+
6
+ This is a preprocessor for ISO Schematron, which implements abstract patterns.
7
+ It also
8
+ * extracts a particular schema using an ID, where there are multiple
9
+ schemas, such as when they are embedded in the same NVDL script
10
+ * experimentally, allows parameter recognition and substitution inside
11
+ text as well as @context, @test, & @select.
12
+
13
+
14
+ This should be used after iso-dsdl-include.xsl and before the skeleton or
15
+ meta-stylesheet (e.g. iso-svrl.xsl) . It only requires XSLT 1.
16
+
17
+ Each kind of inclusion can be turned off (or on) on the command line.
18
+
19
+ -->
20
+ <!--
21
+ VERSION INFORMATION
22
+ 2008-09-18 RJ
23
+ * move out param test from iso:schema template to work with XSLT 1. (Noah Fontes)
24
+
25
+ 2008-07-29 RJ
26
+ * Create. Pull out as distinct XSL in its own namespace from old iso_pre_pro.xsl
27
+ * Put everything in private namespace
28
+ * Rewrite replace_substring named template so that copyright is clear
29
+
30
+ 2008-07-24 RJ
31
+ * correct abstract patterns so for correct names: param/@name and
32
+ param/@value
33
+
34
+ 2007-01-12 RJ
35
+ * Use ISO namespace
36
+ * Use pattern/@id not pattern/@name
37
+ * Add Oliver Becker's suggests from old Schematron-love-in list for <copy>
38
+ * Add XT -ism?
39
+ 2003 RJ
40
+ * Original written for old namespace
41
+ * http://www.topologi.com/resources/iso-pre-pro.xsl
42
+ -->
43
+ <!--
44
+ LEGAL INFORMATION
45
+
46
+ Copyright (c) 2000-2008 Rick Jelliffe and Academia Sinica Computing Center, Taiwan
47
+
48
+ This software is provided 'as-is', without any express or implied warranty.
49
+ In no event will the authors be held liable for any damages arising from
50
+ the use of this software.
51
+
52
+ Permission is granted to anyone to use this software for any purpose,
53
+ including commercial applications, and to alter it and redistribute it freely,
54
+ subject to the following restrictions:
55
+
56
+ 1. The origin of this software must not be misrepresented; you must not claim
57
+ that you wrote the original software. If you use this software in a product,
58
+ an acknowledgment in the product documentation would be appreciated but is
59
+ not required.
60
+
61
+ 2. Altered source versions must be plainly marked as such, and must not be
62
+ misrepresented as being the original software.
63
+
64
+ 3. This notice may not be removed or altered from any source distribution.
65
+ -->
66
+ <xslt:stylesheet version="1.0" xmlns:xslt="http://www.w3.org/1999/XSL/Transform"
67
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
68
+ xmlns:iso="http://purl.oclc.org/dsdl/schematron"
69
+ xmlns:nvdl="http://purl.oclc.org/dsdl/nvdl"
70
+
71
+ xmlns:iae="http://www.schematron.com/namespace/iae"
72
+
73
+ >
74
+
75
+ <xslt:param name="schema-id"></xslt:param>
76
+
77
+
78
+ <!-- Driver for the mode -->
79
+ <xsl:template match="/">
80
+ <xsl:apply-templates select="." mode="iae:go" />
81
+ </xsl:template>
82
+
83
+
84
+ <!-- ================================================================================== -->
85
+ <!-- Normal processing rules -->
86
+ <!-- ================================================================================== -->
87
+ <!-- Output only the selected schema -->
88
+ <xslt:template match="iso:schema" >
89
+ <xsl:if test="string-length($schema-id) =0 or @id= $schema-id ">
90
+ <xslt:copy>
91
+ <xslt:copy-of select="@*" />
92
+ <xslt:apply-templates mode="iae:go" />
93
+ </xslt:copy>
94
+ </xsl:if>
95
+ </xslt:template>
96
+
97
+
98
+ <!-- Strip out any foreign elements above the Schematron schema .
99
+ -->
100
+ <xslt:template match="*[not(ancestor-or-self::iso:*)]" mode="iae:go" >
101
+ <xslt:apply-templates mode="iae:go" />
102
+ </xslt:template>
103
+
104
+
105
+ <!-- ================================================================================== -->
106
+ <!-- Handle Schematron abstract pattern preprocessing -->
107
+ <!-- abstract-to-real calls
108
+ do-pattern calls
109
+ macro-expand calls
110
+ multi-macro-expand
111
+ replace-substring -->
112
+ <!-- ================================================================================== -->
113
+
114
+ <!--
115
+ Abstract patterns allow you to say, for example
116
+
117
+ <pattern name="htmlTable" is-a="table">
118
+ <param name="row" value="html:tr"/>
119
+ <param name="cell" value="html:td" />
120
+ <param name="table" value="html:table" />
121
+ </pattern>
122
+
123
+ For a good introduction, see Uche Ogbujii's article for IBM DeveloperWorks
124
+ "Discover the flexibility of Schematron abstract patterns"
125
+ http://www-128.ibm.com/developerworks/xml/library/x-stron.html
126
+ However, note that ISO Schematron uses @name and @value attributes on
127
+ the iso:param element, and @id not @name on the pattern element.
128
+
129
+ -->
130
+
131
+ <!-- Suppress declarations of abstract patterns -->
132
+ <xslt:template match="iso:pattern[@abstract='true']" mode="iae:go" >
133
+ <xslt:comment>Suppressed abstract pattern <xslt:value-of select="@id"/> was here</xslt:comment>
134
+ </xslt:template>
135
+
136
+
137
+ <!-- Suppress uses of abstract patterns -->
138
+ <xslt:template match="iso:pattern[@is-a]" mode="iae:go" >
139
+
140
+ <xslt:comment>Start pattern based on abstract <xslt:value-of select="@is-a"/></xslt:comment>
141
+
142
+ <xslt:call-template name="iae:abstract-to-real" >
143
+ <xslt:with-param name="caller" select="@id" />
144
+ <xslt:with-param name="is-a" select="@is-a" />
145
+ </xslt:call-template>
146
+
147
+ </xslt:template>
148
+
149
+
150
+
151
+ <!-- output everything else unchanged -->
152
+ <xslt:template match="*" priority="-1" mode="iae:go" >
153
+ <xslt:copy>
154
+ <xslt:copy-of select="@*" />
155
+ <xslt:apply-templates mode="iae:go"/>
156
+ </xslt:copy>
157
+ </xslt:template>
158
+
159
+ <!-- Templates for macro expansion of abstract patterns -->
160
+ <!-- Sets up the initial conditions for the recursive call -->
161
+ <xslt:template name="iae:macro-expand">
162
+ <xslt:param name="caller"/>
163
+ <xslt:param name="text" />
164
+ <xslt:call-template name="iae:multi-macro-expand">
165
+ <xslt:with-param name="caller" select="$caller"/>
166
+ <xslt:with-param name="text" select="$text"/>
167
+ <xslt:with-param name="paramNumber" select="1"/>
168
+ </xslt:call-template>
169
+
170
+ </xslt:template>
171
+
172
+ <!-- Template to replace the current parameter and then
173
+ recurse to replace subsequent parameters. -->
174
+
175
+ <xslt:template name="iae:multi-macro-expand">
176
+ <xslt:param name="caller"/>
177
+ <xslt:param name="text" />
178
+ <xslt:param name="paramNumber" />
179
+
180
+
181
+ <xslt:choose>
182
+ <xslt:when test="//iso:pattern[@id=$caller]/iso:param[ $paramNumber]">
183
+
184
+ <xslt:call-template name="iae:multi-macro-expand">
185
+ <xslt:with-param name="caller" select="$caller"/>
186
+ <xslt:with-param name="paramNumber" select="$paramNumber + 1"/>
187
+ <xslt:with-param name="text" >
188
+ <xslt:call-template name="iae:replace-substring">
189
+ <xslt:with-param name="original" select="$text"/>
190
+ <xslt:with-param name="substring"
191
+ select="concat('$', //iso:pattern[@id=$caller]/iso:param[ $paramNumber ]/@name)"/>
192
+ <xslt:with-param name="replacement"
193
+ select="//iso:pattern[@id=$caller]/iso:param[ $paramNumber ]/@value"/>
194
+ </xslt:call-template>
195
+ </xslt:with-param>
196
+ </xslt:call-template>
197
+ </xslt:when>
198
+ <xslt:otherwise><xslt:value-of select="$text" /></xslt:otherwise>
199
+
200
+ </xslt:choose>
201
+ </xslt:template>
202
+
203
+
204
+ <!-- generate the real pattern from an abstract pattern + parameters-->
205
+ <xslt:template name="iae:abstract-to-real" >
206
+ <xslt:param name="caller"/>
207
+ <xslt:param name="is-a" />
208
+ <xslt:for-each select="//iso:pattern[@id= $is-a]">
209
+ <xslt:copy>
210
+
211
+ <xslt:choose>
212
+ <xslt:when test=" string-length( $caller ) = 0">
213
+ <xslt:attribute name="id"><xslt:value-of select="concat( generate-id(.) , $is-a)" /></xslt:attribute>
214
+ </xslt:when>
215
+ <xslt:otherwise>
216
+ <xslt:attribute name="id"><xslt:value-of select="$caller" /></xslt:attribute>
217
+ </xslt:otherwise>
218
+ </xslt:choose>
219
+
220
+ <xslt:apply-templates select="*|text()" mode="iae:do-pattern" >
221
+ <xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
222
+ </xslt:apply-templates>
223
+
224
+ </xslt:copy>
225
+ </xslt:for-each>
226
+ </xslt:template>
227
+
228
+
229
+ <!-- Generate a non-abstract pattern -->
230
+ <xslt:template mode="iae:do-pattern" match="*">
231
+ <xslt:param name="caller"/>
232
+ <xslt:copy>
233
+ <xslt:for-each select="@*[name()='test' or name()='context' or name()='select']">
234
+ <xslt:attribute name="{name()}">
235
+ <xslt:call-template name="iae:macro-expand">
236
+ <xslt:with-param name="text"><xslt:value-of select="."/></xslt:with-param>
237
+ <xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
238
+ </xslt:call-template>
239
+ </xslt:attribute>
240
+ </xslt:for-each>
241
+ <xslt:copy-of select="@*[name()!='test'][name()!='context'][name()!='select']" />
242
+ <xsl:for-each select="node()">
243
+ <xsl:choose>
244
+ <!-- Experiment: replace macros in text as well, to allow parameterized assertions
245
+ and so on, without having to have spurious <iso:value-of> calls and multiple
246
+ delimiting -->
247
+ <xsl:when test="self::text()">
248
+ <xslt:call-template name="iae:macro-expand">
249
+ <xslt:with-param name="text"><xslt:value-of select="."/></xslt:with-param>
250
+ <xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
251
+ </xslt:call-template>
252
+ </xsl:when>
253
+ <xsl:otherwise>
254
+ <xslt:apply-templates select="." mode="iae:do-pattern">
255
+ <xslt:with-param name="caller"><xslt:value-of select="$caller"/></xslt:with-param>
256
+ </xslt:apply-templates>
257
+ </xsl:otherwise>
258
+ </xsl:choose>
259
+ </xsl:for-each>
260
+ </xslt:copy>
261
+ </xslt:template>
262
+
263
+ <!-- UTILITIES -->
264
+ <!-- Simple version of replace-substring function -->
265
+ <xslt:template name="iae:replace-substring">
266
+ <xslt:param name="original" />
267
+ <xslt:param name="substring" />
268
+ <xslt:param name="replacement" select="''"/>
269
+
270
+ <xsl:choose>
271
+ <xsl:when test="not($original)" />
272
+ <xsl:when test="not(string($substring))">
273
+ <xsl:value-of select="$original" />
274
+ </xsl:when>
275
+ <xsl:when test="contains($original, $substring)">
276
+ <xsl:variable name="before" select="substring-before($original, $substring)" />
277
+ <xsl:variable name="after" select="substring-after($original, $substring)" />
278
+
279
+ <xsl:value-of select="$before" />
280
+ <xsl:value-of select="$replacement" />
281
+ <!-- recursion -->
282
+ <xsl:call-template name="iae:replace-substring">
283
+ <xsl:with-param name="original" select="$after" />
284
+ <xsl:with-param name="substring" select="$substring" />
285
+ <xsl:with-param name="replacement" select="$replacement" />
286
+ </xsl:call-template>
287
+ </xsl:when>
288
+ <xsl:otherwise>
289
+ <!-- no substitution -->
290
+ <xsl:value-of select="$original" />
291
+ </xsl:otherwise>
292
+ </xsl:choose>
293
+ </xslt:template>
294
+
295
+
296
+
297
+ </xslt:stylesheet>