001package org.hl7.fhir.utilities.xml; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2017 University Health Network 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023 024import java.io.IOException; 025import java.io.OutputStream; 026import java.io.UnsupportedEncodingException; 027import java.util.ArrayList; 028import java.util.List; 029 030import org.hl7.fhir.utilities.TextStreamWriter; 031import org.hl7.fhir.utilities.Utilities; 032 033 034public class SchematronWriter extends TextStreamWriter { 035 036 public enum SchematronType { 037 ALL_RESOURCES, 038 RESOURCE, 039 PROFILE 040 } 041 042 public class Assert { 043 private String test; 044 private String message; 045 } 046 047 public class Rule { 048 private String name; 049 private List<Assert> asserts = new ArrayList<Assert>(); 050 public void assrt(String test, String message) { 051 Assert a = new Assert(); 052 a.test = test; 053 a.message = message; 054 asserts.add(a); 055 } 056 } 057 public class Section { 058 private String title; 059 private List<Rule> rules = new ArrayList<Rule>(); 060 061 public String getTitle() { 062 return title; 063 } 064 065 public void setTitle(String title) { 066 this.title = title; 067 } 068 069 public Rule rule(String name) { 070 for (Rule r : rules) { 071 if (r.name.equals(name)) 072 return r; 073 } 074 Rule r = new Rule(); 075 r.name = name; 076 rules.add(r); 077 return r; 078 } 079 } 080 081 private SchematronType type; 082 private String description; 083 private List<Section> sections = new ArrayList<Section>(); 084 085 086 public SchematronWriter(OutputStream out, SchematronType type, String description) throws UnsupportedEncodingException { 087 super(out); 088 this.type = type; 089 this.description = description; 090 } 091 092 public Section section(String title) { 093 for (Section s : sections) { 094 if (s.title.equals(title)) 095 return s; 096 } 097 Section s = new Section(); 098 s.title = title; 099 sections.add(s); 100 return s; 101 } 102 103 public void dump() throws IOException { 104 ln("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); 105 ln_i("<sch:schema xmlns:sch=\"http://purl.oclc.org/dsdl/schematron\" queryBinding=\"xslt2\">"); 106 ln("<sch:ns prefix=\"f\" uri=\"http://hl7.org/fhir\"/>"); 107 ln("<sch:ns prefix=\"h\" uri=\"http://www.w3.org/1999/xhtml\"/>"); 108 addNote(); 109 110 for (Section s : sections) { 111 ln_i("<sch:pattern>"); 112 ln("<sch:title>"+s.title+"</sch:title>"); 113 for (Rule r : s.rules) { 114 if (!r.asserts.isEmpty()) { 115 ln_i("<sch:rule context=\""+r.name+"\">"); 116 for (Assert a : r.asserts) 117 ln("<sch:assert test=\""+Utilities.escapeXml(a.test)+"\">"+Utilities.escapeXml(a.message)+"</sch:assert>"); 118 ln_o("</sch:rule>"); 119 } 120 } 121 ln_o("</sch:pattern>"); 122 } 123 ln_o("</sch:schema>"); 124 flush(); 125 close(); 126 } 127 128 private void addNote() throws IOException { 129 switch (type) { 130 case ALL_RESOURCES : addAllResourcesNote(); break; 131 case RESOURCE : addResourceNote(); break; 132 case PROFILE : addProfileNote(); break; 133 } 134 } 135 136 private void addAllResourcesNote() throws IOException { 137 ln("<!-- "); 138 ln(" This file contains constraints for all resources"); 139 ln(" Because of the way containment works, this file should always )"); 140 ln(" be used for validating resources. Alternatively you can use "); 141 ln(" the resource specific files to build a smaller version of"); 142 ln(" this file (the contents are identical; only include those "); 143 ln(" resources relevant to your implementation)."); 144 ln("-->"); 145 } 146 147 private void addResourceNote() throws IOException { 148 ln("<!-- "); 149 ln(" This file contains just the constraints for the resource "+description); 150 ln(" It is provided for documentation purposes. When actually validating,"); 151 ln(" always use fhir-invariants.sch (because of the way containment works)"); 152 ln(" Alternatively you can use this file to build a smaller version of"); 153 ln(" fhir-invariants.sch (the contents are identical; only include those "); 154 ln(" resources relevant to your implementation)."); 155 ln("-->"); 156 } 157 158 private void addProfileNote() throws IOException { 159 ln("<!-- "); 160 ln(" This file contains just the constraints for the profile "+description); 161 ln(" It includes the base constraints for the resource as well."); 162 ln(" Because of the way that schematrons and containment work, "); 163 ln(" you may need to use this schematron fragment to build a, "); 164 ln(" single schematron that validates contained resources (if you have any) "); 165 ln("-->"); 166 167 } 168 169}