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