schematron-wrapper 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ require 'schematron/version'
2
+ require 'schematron/utils'
3
+ require 'schematron/xslt2'
4
+
5
+ module Schematron
6
+ end
@@ -0,0 +1,29 @@
1
+ require 'tempfile'
2
+
3
+ module Schematron
4
+ module Utils
5
+ def create_temp_file(content, &block)
6
+ temp_file = Tempfile.new('temp_file')
7
+ temp_file.write(content)
8
+ temp_file.rewind
9
+
10
+ begin
11
+ block.call(temp_file)
12
+ ensure
13
+ temp_file.close
14
+ temp_file.unlink
15
+ end
16
+ end
17
+
18
+ def get_attribute_value(element, xpath)
19
+ result = ''
20
+ attributes = element.xpath(xpath)
21
+
22
+ if attributes.size > 0
23
+ result = attributes.first.value
24
+ end
25
+
26
+ result
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,4 @@
1
+ module Schematron
2
+ VERSION = '1.0.0'
3
+ end
4
+
@@ -0,0 +1,71 @@
1
+ require 'nokogiri'
2
+
3
+ module Schematron
4
+ module XSLT2
5
+ extend Schematron::Utils
6
+
7
+ ISO_IMPL_DIR = File.join(File.dirname(__FILE__), '../..', 'iso-schematron-xslt2')
8
+ DSDL_INCLUDES_PATH = File.join(ISO_IMPL_DIR, 'iso_dsdl_include.xsl')
9
+ ABSTRACT_EXPAND_PATH = File.join(ISO_IMPL_DIR, 'iso_abstract_expand.xsl')
10
+ SVRL_FOR_XSLT2_PATH = File.join(ISO_IMPL_DIR, 'iso_svrl_for_xslt2.xsl')
11
+ EXE_PATH = File.join(File.dirname(__FILE__), '../..', 'bin/saxon9he.jar')
12
+
13
+ def self.compile(schematron)
14
+ temp_schematron = process_includes(schematron)
15
+ temp_schematron = expand_abstract_patterns(temp_schematron)
16
+
17
+ create_stylesheet(temp_schematron)
18
+ end
19
+
20
+ def self.validate(stylesheet, xml)
21
+ create_temp_file(stylesheet) do |temp_stylesheet|
22
+ create_temp_file(xml) do |temp_xml|
23
+ execute_transform(temp_stylesheet.path, temp_xml.path)
24
+ end
25
+ end
26
+ end
27
+
28
+ def self.get_errors(validation_result)
29
+ result = []
30
+
31
+ document = Nokogiri::XML(validation_result) do |config|
32
+ config.options = Nokogiri::XML::ParseOptions::NOBLANKS | Nokogiri::XML::ParseOptions::NOENT
33
+ end
34
+
35
+ document.xpath('//svrl:failed-assert').each do |element|
36
+ result.push({message: element.xpath('./svrl:text').text.strip,
37
+ role: get_attribute_value(element, '@role'),
38
+ location: get_attribute_value(element, '@location')})
39
+ end
40
+
41
+ result
42
+ end
43
+
44
+ private
45
+
46
+ def self.process_includes(content_to_transform)
47
+ create_temp_file(content_to_transform) { |temp_file| execute_transform(DSDL_INCLUDES_PATH, temp_file.path) }
48
+ end
49
+
50
+ def self.expand_abstract_patterns(content_to_transform)
51
+ create_temp_file(content_to_transform) { |temp_file| execute_transform(ABSTRACT_EXPAND_PATH, temp_file.path) }
52
+ end
53
+
54
+ def self.create_stylesheet(content_to_transform)
55
+ create_temp_file(content_to_transform) { |temp_file| execute_transform(SVRL_FOR_XSLT2_PATH, temp_file.path, true) }
56
+ end
57
+
58
+ def self.execute_transform(stylesheet, schema, allow_foreign = false)
59
+ cmd = "java -cp #{EXE_PATH} net.sf.saxon.Transform"
60
+
61
+ cmd << " -xsl:#{stylesheet}"
62
+ cmd << " -s:#{schema}"
63
+
64
+ if allow_foreign
65
+ cmd << ' allow-foreign=true'
66
+ end
67
+
68
+ %x{#{cmd}}
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'schematron/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'schematron-wrapper'
8
+ spec.version = Schematron::VERSION
9
+
10
+ spec.authors = ['AgileFreaks']
11
+ spec.email = ['office@agilefreaks.com']
12
+ spec.description = 'A ruby gem that wrappers various schematron implementations so they can be easily used in ruby'
13
+
14
+ spec.homepage = 'https://github.com/Agilefreaks/schematron-wrapper'
15
+ spec.require_paths = ['lib']
16
+ spec.rubygems_version = '1.0.0'
17
+ spec.summary = 'Schematron XSLT 2.0 validator using Saxon9-HE'
18
+
19
+ spec.license = 'Mozilla Public License, version 2.0'
20
+ spec.files = `git ls-files -z`.split("\x0")
21
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
+
24
+ spec.add_development_dependency 'nokogiri', '~> 1.6'
25
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Schematron::XSLT2 do
4
+ SAMPLES_DIR = File.expand_path('../../../../spec/support/samples', __FILE__)
5
+
6
+ describe 'compile' do
7
+ subject { Schematron::XSLT2.compile(input_file) }
8
+
9
+ context 'parameter is schematron' do
10
+ let(:input_file) { File.read(File.join(SAMPLES_DIR, 'initial.sch')) }
11
+
12
+ it { should eq File.read(File.join(SAMPLES_DIR, 'compiled.xsl')) }
13
+ end
14
+ end
15
+
16
+ describe 'validate' do
17
+ let(:stylesheet_file) { File.read(File.join(SAMPLES_DIR, 'compiled.xsl')) }
18
+ let(:target_xml) { File.read(File.join(SAMPLES_DIR, 'target.xml')) }
19
+
20
+ subject { Schematron::XSLT2.validate(stylesheet_file, target_xml).gsub(/"file[^"]*/, '').gsub(/[\s]/, '') }
21
+
22
+ it { should == File.read(File.join(SAMPLES_DIR, 'validation_result.xml')).gsub(/"file[^"]*/, '').gsub(/[\s]/, '') }
23
+ end
24
+
25
+ describe 'get_errors' do
26
+ subject { Schematron::XSLT2.get_errors(validation_result) }
27
+
28
+ context 'validation result has errors' do
29
+ let(:validation_result) { File.read(File.join(SAMPLES_DIR, 'validation_result.xml')) }
30
+
31
+ its(:size) { should eq 2 }
32
+
33
+ its(:first) {
34
+ should include(
35
+ message: 'ePatient.13 - Gender is 9906001 (Female), but eHistory.18 - Pregnancy is 3118011 while it must be 3118003 (Possible, Uncomfirmed).',
36
+ location: "/*:EMSDataSet[namespace-uri()='http://www.nemsis.org'][1]/*:Header[namespace-uri()='http://www.nemsis.org'][1]/*:PatientCareReport[namespace-uri()='http://www.nemsis.org'][1]",
37
+ role: '[FATAL]'
38
+ )
39
+ }
40
+
41
+ its(:last) {
42
+ should include(
43
+ message: 'eTimes.03 - Unit Notified by Dispatch Date/Time 2013-10-02T14:00:50+07:00 should be before eTimes.13 - Unit Back in Service Date/Time 2013-10-02T14:00:50+07:00.',
44
+ location: "/*:EMSDataSet[namespace-uri()='http://www.nemsis.org'][1]/*:Header[namespace-uri()='http://www.nemsis.org'][1]/*:PatientCareReport[namespace-uri()='http://www.nemsis.org'][1]/*:eTimes[namespace-uri()='http://www.nemsis.org'][1]",
45
+ role: '[FATAL]'
46
+ )
47
+ }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,4 @@
1
+ require 'schematron'
2
+ require 'rspec'
3
+
4
+ Dir[File.dirname(__FILE__)+('/support/**/*.rb')].each { |f| require f }
@@ -0,0 +1,334 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2
+ <xsl:stylesheet xmlns:xs="http://www.w3.org/2001/XMLSchema"
3
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
4
+ xmlns:saxon="http://saxon.sf.net/"
5
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
6
+ xmlns:schold="http://www.ascc.net/xml/schematron"
7
+ xmlns:iso="http://purl.oclc.org/dsdl/schematron"
8
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
9
+ xmlns:nem="http://www.nemsis.org"
10
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
11
+ xmlns:fct="localFunctions"
12
+ version="2.0"><!--Implementers: please note that overriding process-prolog or process-root is
13
+ the preferred method for meta-stylesheets to use where possible. -->
14
+ <xsl:param name="archiveDirParameter"/>
15
+ <xsl:param name="archiveNameParameter"/>
16
+ <xsl:param name="fileNameParameter"/>
17
+ <xsl:param name="fileDirParameter"/>
18
+ <xsl:variable name="document-uri">
19
+ <xsl:value-of select="document-uri(/)"/>
20
+ </xsl:variable>
21
+
22
+ <!--PHASES-->
23
+
24
+
25
+ <!--PROLOG-->
26
+ <xsl:output xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
27
+ method="xml"
28
+ omit-xml-declaration="no"
29
+ standalone="yes"
30
+ indent="yes"/>
31
+
32
+ <!--XSD TYPES FOR XSLT2-->
33
+
34
+
35
+ <!--KEYS AND FUNCTIONS-->
36
+
37
+
38
+ <!--DEFAULT RULES-->
39
+
40
+
41
+ <!--MODE: SCHEMATRON-SELECT-FULL-PATH-->
42
+ <!--This mode can be used to generate an ugly though full XPath for locators-->
43
+ <xsl:template match="*" mode="schematron-select-full-path">
44
+ <xsl:apply-templates select="." mode="schematron-get-full-path"/>
45
+ </xsl:template>
46
+
47
+ <!--MODE: SCHEMATRON-FULL-PATH-->
48
+ <!--This mode can be used to generate an ugly though full XPath for locators-->
49
+ <xsl:template match="*" mode="schematron-get-full-path">
50
+ <xsl:apply-templates select="parent::*" mode="schematron-get-full-path"/>
51
+ <xsl:text>/</xsl:text>
52
+ <xsl:choose>
53
+ <xsl:when test="namespace-uri()=''">
54
+ <xsl:value-of select="name()"/>
55
+ </xsl:when>
56
+ <xsl:otherwise>
57
+ <xsl:text>*:</xsl:text>
58
+ <xsl:value-of select="local-name()"/>
59
+ <xsl:text>[namespace-uri()='</xsl:text>
60
+ <xsl:value-of select="namespace-uri()"/>
61
+ <xsl:text>']</xsl:text>
62
+ </xsl:otherwise>
63
+ </xsl:choose>
64
+ <xsl:variable name="preceding"
65
+ select="count(preceding-sibling::*[local-name()=local-name(current()) and namespace-uri() = namespace-uri(current())])"/>
66
+ <xsl:text>[</xsl:text>
67
+ <xsl:value-of select="1+ $preceding"/>
68
+ <xsl:text>]</xsl:text>
69
+ </xsl:template>
70
+ <xsl:template match="@*" mode="schematron-get-full-path">
71
+ <xsl:apply-templates select="parent::*" mode="schematron-get-full-path"/>
72
+ <xsl:text>/</xsl:text>
73
+ <xsl:choose>
74
+ <xsl:when test="namespace-uri()=''">@<xsl:value-of select="name()"/>
75
+ </xsl:when>
76
+ <xsl:otherwise>
77
+ <xsl:text>@*[local-name()='</xsl:text>
78
+ <xsl:value-of select="local-name()"/>
79
+ <xsl:text>' and namespace-uri()='</xsl:text>
80
+ <xsl:value-of select="namespace-uri()"/>
81
+ <xsl:text>']</xsl:text>
82
+ </xsl:otherwise>
83
+ </xsl:choose>
84
+ </xsl:template>
85
+
86
+ <!--MODE: SCHEMATRON-FULL-PATH-2-->
87
+ <!--This mode can be used to generate prefixed XPath for humans-->
88
+ <xsl:template match="node() | @*" mode="schematron-get-full-path-2">
89
+ <xsl:for-each select="ancestor-or-self::*">
90
+ <xsl:text>/</xsl:text>
91
+ <xsl:value-of select="name(.)"/>
92
+ <xsl:if test="preceding-sibling::*[name(.)=name(current())]">
93
+ <xsl:text>[</xsl:text>
94
+ <xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1"/>
95
+ <xsl:text>]</xsl:text>
96
+ </xsl:if>
97
+ </xsl:for-each>
98
+ <xsl:if test="not(self::*)">
99
+ <xsl:text/>/@<xsl:value-of select="name(.)"/>
100
+ </xsl:if>
101
+ </xsl:template>
102
+ <!--MODE: SCHEMATRON-FULL-PATH-3-->
103
+ <!--This mode can be used to generate prefixed XPath for humans
104
+ (Top-level element has index)-->
105
+ <xsl:template match="node() | @*" mode="schematron-get-full-path-3">
106
+ <xsl:for-each select="ancestor-or-self::*">
107
+ <xsl:text>/</xsl:text>
108
+ <xsl:value-of select="name(.)"/>
109
+ <xsl:if test="parent::*">
110
+ <xsl:text>[</xsl:text>
111
+ <xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1"/>
112
+ <xsl:text>]</xsl:text>
113
+ </xsl:if>
114
+ </xsl:for-each>
115
+ <xsl:if test="not(self::*)">
116
+ <xsl:text/>/@<xsl:value-of select="name(.)"/>
117
+ </xsl:if>
118
+ </xsl:template>
119
+
120
+ <!--MODE: GENERATE-ID-FROM-PATH -->
121
+ <xsl:template match="/" mode="generate-id-from-path"/>
122
+ <xsl:template match="text()" mode="generate-id-from-path">
123
+ <xsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
124
+ <xsl:value-of select="concat('.text-', 1+count(preceding-sibling::text()), '-')"/>
125
+ </xsl:template>
126
+ <xsl:template match="comment()" mode="generate-id-from-path">
127
+ <xsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
128
+ <xsl:value-of select="concat('.comment-', 1+count(preceding-sibling::comment()), '-')"/>
129
+ </xsl:template>
130
+ <xsl:template match="processing-instruction()" mode="generate-id-from-path">
131
+ <xsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
132
+ <xsl:value-of select="concat('.processing-instruction-', 1+count(preceding-sibling::processing-instruction()), '-')"/>
133
+ </xsl:template>
134
+ <xsl:template match="@*" mode="generate-id-from-path">
135
+ <xsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
136
+ <xsl:value-of select="concat('.@', name())"/>
137
+ </xsl:template>
138
+ <xsl:template match="*" mode="generate-id-from-path" priority="-0.5">
139
+ <xsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
140
+ <xsl:text>.</xsl:text>
141
+ <xsl:value-of select="concat('.',name(),'-',1+count(preceding-sibling::*[name()=name(current())]),'-')"/>
142
+ </xsl:template>
143
+
144
+ <!--MODE: GENERATE-ID-2 -->
145
+ <xsl:template match="/" mode="generate-id-2">U</xsl:template>
146
+ <xsl:template match="*" mode="generate-id-2" priority="2">
147
+ <xsl:text>U</xsl:text>
148
+ <xsl:number level="multiple" count="*"/>
149
+ </xsl:template>
150
+ <xsl:template match="node()" mode="generate-id-2">
151
+ <xsl:text>U.</xsl:text>
152
+ <xsl:number level="multiple" count="*"/>
153
+ <xsl:text>n</xsl:text>
154
+ <xsl:number count="node()"/>
155
+ </xsl:template>
156
+ <xsl:template match="@*" mode="generate-id-2">
157
+ <xsl:text>U.</xsl:text>
158
+ <xsl:number level="multiple" count="*"/>
159
+ <xsl:text>_</xsl:text>
160
+ <xsl:value-of select="string-length(local-name(.))"/>
161
+ <xsl:text>_</xsl:text>
162
+ <xsl:value-of select="translate(name(),':','.')"/>
163
+ </xsl:template>
164
+ <!--Strip characters-->
165
+ <xsl:template match="text()" priority="-1"/>
166
+
167
+ <!--SCHEMA SETUP-->
168
+ <xsl:template match="/">
169
+ <svrl:schematron-output xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
170
+ title="NEMSIS Compliance Test ISO Schematron File"
171
+ schemaVersion="">
172
+ <xsl:comment>
173
+ <xsl:value-of select="$archiveDirParameter"/>  
174
+ <xsl:value-of select="$archiveNameParameter"/>  
175
+ <xsl:value-of select="$fileNameParameter"/>  
176
+ <xsl:value-of select="$fileDirParameter"/>
177
+ </xsl:comment>
178
+ <svrl:ns-prefix-in-attribute-values uri="http://www.nemsis.org" prefix="nem"/>
179
+ <svrl:ns-prefix-in-attribute-values uri="http://www.w3.org/1999/XSL/Transform" prefix="xsl"/>
180
+ <svrl:ns-prefix-in-attribute-values uri="http://www.w3.org/2001/XMLSchema-instance" prefix="xsi"/>
181
+ <svrl:ns-prefix-in-attribute-values uri="localFunctions" prefix="fct"/>
182
+ <svrl:active-pattern>
183
+ <xsl:attribute name="document">
184
+ <xsl:value-of select="document-uri(/)"/>
185
+ </xsl:attribute>
186
+ <xsl:attribute name="id">complianceTestStructureRule1</xsl:attribute>
187
+ <xsl:attribute name="name">When ePatient.13 is 9906001, eHistory.18 must be 3118003.</xsl:attribute>
188
+ <xsl:apply-templates/>
189
+ </svrl:active-pattern>
190
+ <xsl:apply-templates select="/" mode="M5"/>
191
+ <svrl:active-pattern>
192
+ <xsl:attribute name="document">
193
+ <xsl:value-of select="document-uri(/)"/>
194
+ </xsl:attribute>
195
+ <xsl:attribute name="id">complianceTestStructureRule2</xsl:attribute>
196
+ <xsl:attribute name="name">eTimes.03 - Unit Notied by Dispatch Date/Time is before eTimes.13 - Unit Back in Service Date/Time</xsl:attribute>
197
+ <xsl:apply-templates/>
198
+ </svrl:active-pattern>
199
+ <xsl:apply-templates select="/" mode="M6"/>
200
+ <svrl:active-pattern>
201
+ <xsl:attribute name="document">
202
+ <xsl:value-of select="document-uri(/)"/>
203
+ </xsl:attribute>
204
+ <xsl:attribute name="id">complianceTestStructureRule3</xsl:attribute>
205
+ <xsl:attribute name="name">eDispatch.01 - Complaint Reported by Dispatch must not be 2301069</xsl:attribute>
206
+ <xsl:apply-templates/>
207
+ </svrl:active-pattern>
208
+ <xsl:apply-templates select="/" mode="M7"/>
209
+ </svrl:schematron-output>
210
+ </xsl:template>
211
+
212
+ <!--SCHEMATRON PATTERNS-->
213
+ <svrl:text xmlns:svrl="http://purl.oclc.org/dsdl/svrl">NEMSIS Compliance Test ISO Schematron File</svrl:text>
214
+
215
+ <!--PATTERN complianceTestStructureRule1When ePatient.13 is 9906001, eHistory.18 must be 3118003.-->
216
+ <svrl:text xmlns:svrl="http://purl.oclc.org/dsdl/svrl">When ePatient.13 is 9906001, eHistory.18 must be 3118003.</svrl:text>
217
+
218
+ <!--RULE -->
219
+ <xsl:template match="nem:Header/nem:PatientCareReport" priority="1000" mode="M5">
220
+ <svrl:fired-rule xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
221
+ context="nem:Header/nem:PatientCareReport"
222
+ role="[FATAL]"/>
223
+ <xsl:variable name="patientCare" select="normalize-space(.)"/>
224
+ <xsl:variable name="ePatient13"
225
+ select="normalize-space(./nem:ePatient/nem:ePatient.13/.)"/>
226
+ <xsl:variable name="eHistory18"
227
+ select="normalize-space(./nem:eHistory/nem:eHistory.18/.)"/>
228
+
229
+ <!--ASSERT [FATAL]-->
230
+ <xsl:choose>
231
+ <xsl:when test="if (number($ePatient13) = 9906001) then (if (number($eHistory18) = 3118003) then true() else false()) else true()"/>
232
+ <xsl:otherwise>
233
+ <svrl:failed-assert xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
234
+ test="if (number($ePatient13) = 9906001) then (if (number($eHistory18) = 3118003) then true() else false()) else true()">
235
+ <xsl:attribute name="role">[FATAL]</xsl:attribute>
236
+ <xsl:attribute name="location">
237
+ <xsl:apply-templates select="." mode="schematron-select-full-path"/>
238
+ </xsl:attribute>
239
+ <svrl:text>
240
+ ePatient.13 - Gender is 9906001 (Female), but eHistory.18 - Pregnancy is <xsl:text/>
241
+ <xsl:value-of select="$eHistory18"/>
242
+ <xsl:text/> while it must be 3118003 (Possible, Uncomfirmed).
243
+ </svrl:text>
244
+ </svrl:failed-assert>
245
+ </xsl:otherwise>
246
+ </xsl:choose>
247
+ <xsl:apply-templates select="*|comment()|processing-instruction()" mode="M5"/>
248
+ </xsl:template>
249
+ <xsl:template match="text()" priority="-1" mode="M5"/>
250
+ <xsl:template match="@*|node()" priority="-2" mode="M5">
251
+ <xsl:apply-templates select="*|comment()|processing-instruction()" mode="M5"/>
252
+ </xsl:template>
253
+
254
+ <!--PATTERN complianceTestStructureRule2eTimes.03 - Unit Notied by Dispatch Date/Time is before eTimes.13 - Unit Back in Service Date/Time-->
255
+ <svrl:text xmlns:svrl="http://purl.oclc.org/dsdl/svrl">eTimes.03 - Unit Notied by Dispatch Date/Time is before eTimes.13 - Unit Back in Service Date/Time</svrl:text>
256
+
257
+ <!--RULE -->
258
+ <xsl:template match="nem:Header/nem:PatientCareReport/nem:eTimes"
259
+ priority="1000"
260
+ mode="M6">
261
+ <svrl:fired-rule xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
262
+ context="nem:Header/nem:PatientCareReport/nem:eTimes"
263
+ role="[FATAL]"/>
264
+ <xsl:variable name="eTimes" select="normalize-space(.)"/>
265
+ <xsl:variable name="eTimes03" select="normalize-space(./nem:eTimes.03/.)"/>
266
+ <xsl:variable name="eTimes13" select="normalize-space(./nem:eTimes.13/.)"/>
267
+ <xsl:variable name="eTimes03All"
268
+ select="normalize-space(concat(substring($eTimes03,1,4), substring($eTimes03,6,2), substring($eTimes03,9,2), substring($eTimes03,12,2), substring($eTimes03,15,2), substring($eTimes03,18,2)))"/>
269
+ <xsl:variable name="eTimes13All"
270
+ select="normalize-space(concat(substring($eTimes13,1,4), substring($eTimes13,6,2), substring($eTimes13,9,2), substring($eTimes13,12,2), substring($eTimes13,15,2), substring($eTimes13,18,2)))"/>
271
+
272
+ <!--ASSERT [FATAL]-->
273
+ <xsl:choose>
274
+ <xsl:when test=" if (number($eTimes03All) &lt; number($eTimes13All)) then true() else false() "/>
275
+ <xsl:otherwise>
276
+ <svrl:failed-assert xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
277
+ test="if (number($eTimes03All) &lt; number($eTimes13All)) then true() else false()">
278
+ <xsl:attribute name="role">[FATAL]</xsl:attribute>
279
+ <xsl:attribute name="location">
280
+ <xsl:apply-templates select="." mode="schematron-select-full-path"/>
281
+ </xsl:attribute>
282
+ <svrl:text>
283
+ eTimes.03 - Unit Notified by Dispatch Date/Time <xsl:text/>
284
+ <xsl:value-of select="$eTimes03"/>
285
+ <xsl:text/> should be before eTimes.13 - Unit Back in Service Date/Time <xsl:text/>
286
+ <xsl:value-of select="$eTimes13"/>
287
+ <xsl:text/>.
288
+ </svrl:text>
289
+ </svrl:failed-assert>
290
+ </xsl:otherwise>
291
+ </xsl:choose>
292
+ <xsl:apply-templates select="*|comment()|processing-instruction()" mode="M6"/>
293
+ </xsl:template>
294
+ <xsl:template match="text()" priority="-1" mode="M6"/>
295
+ <xsl:template match="@*|node()" priority="-2" mode="M6">
296
+ <xsl:apply-templates select="*|comment()|processing-instruction()" mode="M6"/>
297
+ </xsl:template>
298
+
299
+ <!--PATTERN complianceTestStructureRule3eDispatch.01 - Complaint Reported by Dispatch must not be 2301069-->
300
+ <svrl:text xmlns:svrl="http://purl.oclc.org/dsdl/svrl">eDispatch.01 - Complaint Reported by Dispatch must not be 2301069</svrl:text>
301
+
302
+ <!--RULE -->
303
+ <xsl:template match="nem:Header/nem:PatientCareReport/nem:eDispatch"
304
+ priority="1000"
305
+ mode="M7">
306
+ <svrl:fired-rule xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
307
+ context="nem:Header/nem:PatientCareReport/nem:eDispatch"
308
+ role="[FATAL]"/>
309
+ <xsl:variable name="eDispatch" select="normalize-space(.)"/>
310
+ <xsl:variable name="eDispatch01" select="normalize-space(./nem:eDispatch.01/.)"/>
311
+
312
+ <!--ASSERT [FATAL]-->
313
+ <xsl:choose>
314
+ <xsl:when test="if (number($eDispatch01) = 2301007) then false() else true()"/>
315
+ <xsl:otherwise>
316
+ <svrl:failed-assert xmlns:svrl="http://purl.oclc.org/dsdl/svrl"
317
+ test="if (number($eDispatch01) = 2301007) then false() else true()">
318
+ <xsl:attribute name="role">[FATAL]</xsl:attribute>
319
+ <xsl:attribute name="location">
320
+ <xsl:apply-templates select="." mode="schematron-select-full-path"/>
321
+ </xsl:attribute>
322
+ <svrl:text>
323
+ eDispatch.01 - Complaint Reported by Dispatch must NOT be 2301007.
324
+ </svrl:text>
325
+ </svrl:failed-assert>
326
+ </xsl:otherwise>
327
+ </xsl:choose>
328
+ <xsl:apply-templates select="*|comment()|processing-instruction()" mode="M7"/>
329
+ </xsl:template>
330
+ <xsl:template match="text()" priority="-1" mode="M7"/>
331
+ <xsl:template match="@*|node()" priority="-2" mode="M7">
332
+ <xsl:apply-templates select="*|comment()|processing-instruction()" mode="M7"/>
333
+ </xsl:template>
334
+ </xsl:stylesheet>