rework spreadsheet generation to support more resource types

This commit is contained in:
Grahame Grieve 2021-09-01 07:02:00 +10:00
parent 3d1676170a
commit 5a7393c7ec
6 changed files with 1029 additions and 0 deletions

View File

@ -0,0 +1,68 @@
package org.hl7.fhir.r5.renderers.spreadsheets;
import java.io.OutputStream;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.ContactDetail;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.Identifier;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionMappingComponent;
import org.hl7.fhir.r5.renderers.DataRenderer;
public class CanonicalSpreadsheetGenerator extends SpreadsheetGenerator {
public CanonicalSpreadsheetGenerator(IWorkerContext context) {
super(context);
}
protected Sheet renderCanonicalResource(CanonicalResource cr) {
Sheet sheet = wb.createSheet("Metadata");
Row headerRow = sheet.createRow(0);
addCell(headerRow, 0, "Property", styles.get("header"));
addCell(headerRow, 1, "Value", styles.get("header"));
addMetadataRow(sheet, "URL", cr.getUrl());
for (Identifier id : cr.getIdentifier()) {
addMetadataRow(sheet, "Identifier", dr.display(id));
}
addMetadataRow(sheet, "Version", cr.getVersion());
addMetadataRow(sheet, "Name", cr.getName());
addMetadataRow(sheet, "Title", cr.getTitle());
addMetadataRow(sheet, "Status", cr.getStatusElement().asStringValue());
addMetadataRow(sheet, "Experimental", cr.getExperimentalElement().asStringValue());
addMetadataRow(sheet, "Date", cr.getDateElement().asStringValue());
addMetadataRow(sheet, "Publisher", cr.getPublisher());
for (ContactDetail c : cr.getContact()) {
addMetadataRow(sheet, "Contact", dr.display(c));
}
for (CodeableConcept j : cr.getJurisdiction()) {
addMetadataRow(sheet, "Jurisdiction", dr.display(j));
}
addMetadataRow(sheet, "Description", cr.getDescription());
addMetadataRow(sheet, "Purpose", cr.getPurpose());
addMetadataRow(sheet, "Copyright", cr.getCopyright());
configureSheet(sheet);
return sheet;
}
private void configureSheet(Sheet sheet) {
sheet.setColumnWidth(0, columnPixels(15));
sheet.setColumnWidth(1, columnPixels(80));
}
protected void addMetadataRow(Sheet sheet, String name, String value) {
Row row = sheet.createRow(sheet.getLastRowNum()+1);
addCell(row, 0, name, styles.get("body"));
addCell(row, 1, value);
}
}

View File

@ -0,0 +1,215 @@
package org.hl7.fhir.r5.renderers.spreadsheets;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.CodeSystem.CodeSystemFilterComponent;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r5.model.CodeSystem.PropertyComponent;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.Enumeration;
import org.hl7.fhir.r5.model.Enumerations.FilterOperator;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionMappingComponent;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.i18n.I18nConstants;
public class CodeSystemSpreadsheetGenerator extends CanonicalSpreadsheetGenerator {
public CodeSystemSpreadsheetGenerator(IWorkerContext context) {
super(context);
}
public boolean canGenerate(CodeSystem cs) {
return true;
}
public CodeSystemSpreadsheetGenerator renderCodeSystem(CodeSystem cs) throws IOException {
if (cs == null) {
System.out.println("no code system!");
}
addCodeSystemMetadata(renderCanonicalResource(cs), cs);
if (cs.hasProperty()) {
addProperties(cs.getProperty());
}
if (cs.hasFilter()) {
addFilters(cs.getFilter());
}
if (cs.hasConcept()) {
addConcepts(cs.getConcept());
}
return this;
}
private void addCodeSystemMetadata(Sheet sheet, CodeSystem cs) {
addMetadataRow(sheet, "Case Sensitive", cs.getCaseSensitiveElement().asStringValue());
addMetadataRow(sheet, "Value Set (all codes)", cs.getValueSet());
addMetadataRow(sheet, "Hierarchy", cs.getHierarchyMeaningElement().asStringValue());
addMetadataRow(sheet, "Compositional", cs.getCompositionalElement().asStringValue());
addMetadataRow(sheet, "Version Needed?", cs.getVersionNeededElement().asStringValue());
addMetadataRow(sheet, "Content", cs.getContentElement().asStringValue());
addMetadataRow(sheet, "Supplements", cs.getSupplements());
addMetadataRow(sheet, "Count", cs.getCountElement().asStringValue());
}
private void addFilters(List<CodeSystemFilterComponent> filters) {
Sheet sheet = wb.createSheet("Filters");
addHeaders(sheet, "Code", "Description", "Operators", "Value");
for (CodeSystemFilterComponent f : filters) {
CommaSeparatedStringBuilder cs = new CommaSeparatedStringBuilder();
for (Enumeration<FilterOperator> op : f.getOperator()) {
cs.append(op.asStringValue());
}
addRow(sheet, f.getCode(), f.getDescription(), cs.toString(), f.getValue());
}
}
private void addProperties(List<PropertyComponent> properties) {
Sheet sheet = wb.createSheet("Properties");
addHeaders(sheet, "Code", "Uri", "Description", "Type");
for (PropertyComponent p : properties) {
addRow(sheet, p.getCode(), p.getUri(), p.getDescription(), p.getTypeElement().asStringValue());
}
}
private void addConcepts(List<ConceptDefinitionComponent> concepts) {
Sheet sheet = wb.createSheet("Concepts");
addHeaders(sheet, "Level", "Code", "Display", "Definition"); //todo: properties and designations
addConcepts(sheet, 1, concepts);
}
private void addConcepts(Sheet sheet, int i, List<ConceptDefinitionComponent> concepts) {
for (ConceptDefinitionComponent c : concepts) {
addRow(sheet, Integer.toString(i), c.getCode(), c.getDisplay(), c.getDefinition());
if (c.hasConcept()) {
addConcepts(sheet, i+1, c.getConcept());
}
}
}
private void genExpansionParams(List<ValueSetExpansionParameterComponent> params) {
Sheet sheet = wb.createSheet("Expansion Parameters");
addHeaders(sheet, "Parameter", "Value");
for (ValueSetExpansionParameterComponent p : params) {
addRow(sheet, p.getName(), dr.display(p.getValue()));
}
}
private void genExpansion(List<ValueSetExpansionContainsComponent> list) {
Sheet sheet = wb.createSheet("Expansion");
addHeaders(sheet, "Level", "System", "version", "Code", "Display", "Abstract", "Inactive");
genExpansionEntry(1, list, sheet);
}
public void genExpansionEntry(int level, List<ValueSetExpansionContainsComponent> list, Sheet sheet) {
for (ValueSetExpansionContainsComponent p : list) {
addRow(sheet, Integer.toString(level), p.getSystem(), p.getVersion(), p.getCode(), p.getDisplay(), bool(p.getAbstract()), bool(p.getInactive()));
if (p.hasContains()) {
genExpansionEntry(level + 1, p.getContains(), sheet);
}
}
}
private String bool(boolean value) {
return value ? "" : "false";
}
private void genInclude(ValueSet vs, ConceptSetComponent inc, String mode) {
if (inc.hasSystem()) {
genIncludeSystem(vs, inc, mode);
} else {
genIncludeValueSets(vs, inc, mode);
}
// String subname = inc.hasSystem() ? : "ValueSets";
//
//
// Row headerRow = sheet.createRow(0);
// for (int i = 0; i < titles.length; i++) {
// addCell(headerRow, i, titles[i], styles.get("header"));
// }
// int i = titles.length - 1;
// for (StructureDefinitionMappingComponent map : sd.getMapping()) {
// i++;
// addCell(headerRow, i, "Mapping: " + map.getName(), styles.get("header"));
// }
//
// for (ElementDefinition child : sd.getSnapshot().getElement()) {
// processElement(sheet, sd, child);
// }
// configureSheet(sheet, sd);
}
private void genIncludeValueSets(ValueSet vs, ConceptSetComponent inc, String mode) {
Sheet sheet = wb.createSheet(mode+" ValueSets");
addValueSets(sheet, inc.getValueSet());
configureSheet(sheet);
}
private void genIncludeSystem(ValueSet vs, ConceptSetComponent inc, String mode) {
Sheet sheet = wb.createSheet(mode+" from "+dr.displaySystem(inc.getSystem()));
if (inc.hasValueSet()) {
addValueSets(sheet, inc.getValueSet());
}
if (inc.hasFilter()) {
addFilters(sheet, inc.getFilter());
}
if (inc.hasConcept()) {
addConcepts(sheet, inc.getConcept());
}
if (!inc.hasConcept() && !inc.hasFilter()) {
addAllCodes(sheet);
}
addRow(sheet, "", "");
addRow(sheet, "System URI", inc.getSystem());
configureSheet(sheet);
}
private void addAllCodes(Sheet sheet) {
addHeaders(sheet, "Codes");
addRow(sheet, "All codes");
}
private void addValueSets(Sheet sheet, List<CanonicalType> valueSets) {
addHeaders(sheet, "ValueSet URL");
for (CanonicalType u : valueSets) {
addRow(sheet, u.getValue());
}
}
private void configureSheet(Sheet sheet) {
sheet.setColumnWidth(0, columnPixels(30));
sheet.setColumnWidth(1, columnPixels(40));
sheet.setColumnWidth(1, columnPixels(50));
}
private void addConcepts(Sheet sheet, List<ConceptReferenceComponent> concepts) {
addHeaders(sheet, "Concept", "Description"); // todo: designations
for (ConceptReferenceComponent cd : concepts) {
addRow(sheet, cd.getCode(), cd.getDisplay());
}
}
private void addFilters(Sheet sheet, List<ConceptSetFilterComponent> filters) {
addHeaders(sheet, "Property", "Operation", "Value");
for (ConceptSetFilterComponent f : filters) {
addRow(sheet, f.getProperty(), f.getOpElement().asStringValue(), f.getValue());
}
}
}

View File

@ -0,0 +1,51 @@
package org.hl7.fhir.r5.renderers.spreadsheets;
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.Sheet;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.model.ConceptMap;
import org.hl7.fhir.r5.model.ConceptMap.ConceptMapGroupComponent;
import org.hl7.fhir.r5.model.ConceptMap.SourceElementComponent;
import org.hl7.fhir.r5.model.ConceptMap.TargetElementComponent;
public class ConceptMapSpreadsheetGenerator extends CanonicalSpreadsheetGenerator {
public ConceptMapSpreadsheetGenerator(IWorkerContext context) {
super(context);
}
public boolean canGenerate(ConceptMap cm) {
return true;
}
public ConceptMapSpreadsheetGenerator renderConceptMap(ConceptMap cm) {
addConceptMapMetadata(renderCanonicalResource(cm), cm);
int i = 0;
for (ConceptMapGroupComponent grp : cm.getGroup()) {
renderGroup(grp, i);
i++;
}
return this;
}
private void addConceptMapMetadata(Sheet sheet, ConceptMap cm) {
addMetadataRow(sheet, "Source", cm.getSource().primitiveValue());
addMetadataRow(sheet, "Target", cm.getTarget().primitiveValue());
}
private void renderGroup(ConceptMapGroupComponent grp, int i) {
Sheet sheet = wb.createSheet("Mapping Table "+Integer.toString(i));
addHeaders(sheet, "Source", "Display", "Relationship", "Target", "Display");
addRow(sheet, grp.getSource(), "", "", grp.getTarget(), "");
for (SourceElementComponent s : grp.getElement()) {
for (TargetElementComponent t : s.getTarget()) {
addRow(sheet, s.getCode(), s.getDisplay(), t.getRelationshipElement().asStringValue(), t.getCode(), t.getDisplay());
}
}
}
}

View File

@ -0,0 +1,152 @@
package org.hl7.fhir.r5.renderers.spreadsheets;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.renderers.DataRenderer;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
public class SpreadsheetGenerator {
protected IWorkerContext context;
protected XSSFWorkbook wb = new XSSFWorkbook();
protected Map<String, CellStyle> styles;
protected DataRenderer dr;
public SpreadsheetGenerator(IWorkerContext context) {
super();
this.context = context;
styles = createStyles(wb);
dr = new DataRenderer(context);
}
public void finish(OutputStream outStream) throws IOException {
wb.write(outStream);
outStream.flush();
outStream.close();
}
private static Map<String, CellStyle> createStyles(Workbook wb){
Map<String, CellStyle> styles = new HashMap<>();
CellStyle style;
Font headerFont = wb.createFont();
headerFont.setBold(true);
style = createBorderedStyle(wb);
style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style.setVerticalAlignment(VerticalAlignment.TOP);
style.setWrapText(true);
style.setFont(headerFont);
styles.put("header", style);
style = createBorderedStyle(wb);
style.setVerticalAlignment(VerticalAlignment.TOP);
style.setWrapText(true);
styles.put("body", style);
return styles;
}
private static CellStyle createBorderedStyle(Workbook wb){
BorderStyle thin = BorderStyle.THIN;
short black = IndexedColors.GREY_50_PERCENT.getIndex();
CellStyle style = wb.createCellStyle();
style.setBorderRight(thin);
style.setRightBorderColor(black);
style.setBorderBottom(thin);
style.setBottomBorderColor(black);
style.setBorderLeft(thin);
style.setLeftBorderColor(black);
style.setBorderTop(thin);
style.setTopBorderColor(black);
return style;
}
protected void addCell(Row row, int pos, String content) {
addCell(row, pos, content, styles.get("body"));
}
protected void addCell(Row row, int pos, boolean b) {
addCell(row, pos, b ? "Y" : "");
}
protected void addCell(Row row, int pos, int content) {
addCell(row, pos, Integer.toString(content));
}
protected void addCell(Row row, int pos, String content, CellStyle style) {
Cell cell = row.createCell(pos);
cell.setCellValue(content);
cell.setCellStyle(style);
}
protected int columnPixels(double columns) {
double WIDTH_FACTOR = 256;
double PADDING = 180;
return (int)Math.floor(columns*WIDTH_FACTOR + PADDING);
}
protected void addHeaders(Sheet sheet, String... titles) {
Row headerRow = sheet.createRow(sheet.getRow(0) == null ? 0 : sheet.getLastRowNum()+1);
for (int i = 0; i < titles.length; i++) {
addCell(headerRow, i, titles[i], styles.get("header"));
}
}
protected void addRow(Sheet sheet, String... values) {
Row row = sheet.createRow(sheet.getLastRowNum()+1);
for (int i = 0; i < values.length; i++) {
addCell(row, i, values[i], styles.get("body"));
}
}
}

View File

@ -0,0 +1,375 @@
package org.hl7.fhir.r5.renderers.spreadsheets;
import java.io.IOException;
import java.io.OutputStream;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.ConditionalFormattingRule;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.FontFormatting;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.PatternFormatting;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.SheetConditionalFormatting;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellAddress;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.formats.XmlParser;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ElementDefinition.AggregationMode;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionConstraintComponent;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionMappingComponent;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionSlicingDiscriminatorComponent;
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r5.model.IdType;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionContextComponent;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionMappingComponent;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.TextStreamWriter;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAutoFilter;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCustomFilter;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCustomFilters;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFilterColumn;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFilters;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STFilterOperator;
public class StructureDefinitionSpreadsheetGenerator extends CanonicalSpreadsheetGenerator {
private XmlParser xml = new XmlParser();
private JsonParser json = new JsonParser();
private boolean asXml;
private boolean hideMustSupportFalse;
private List<StructureDefinitionMappingComponent> mapKeys = new ArrayList<StructureDefinitionMappingComponent>();
private static String[] titles = {
"Path", "Slice Name", "Alias(s)", "Label", "Min", "Max", "Must Support?", "Is Modifier?", "Is Summary?", "Type(s)", "Short",
"Definition", "Comments", "Requirements", "Default Value", "Meaning When Missing", "Fixed Value", "Pattern", "Example",
"Minimum Value", "Maximum Value", "Maximum Length", "Binding Strength", "Binding Description", "Binding Value Set", "Code",
"Slicing Discriminator", "Slicing Description", "Slicing Ordered", "Slicing Rules", "Base Path", "Base Min", "Base Max",
"Condition(s)", "Constraint(s)"};
public StructureDefinitionSpreadsheetGenerator(IWorkerContext context, boolean asXml, boolean hideMustSupportFalse) {
super(context);
this.asXml = asXml;
this.hideMustSupportFalse = hideMustSupportFalse;
}
public StructureDefinitionSpreadsheetGenerator renderStructureDefinition(StructureDefinition sd) throws Exception {
if (sd == null) {
System.out.println("no structure!");
}
if (!sd.hasSnapshot()) {
throw new DefinitionException(context.formatMessage(I18nConstants.NEEDS_A_SNAPSHOT));
}
addStructureDefinitionMetadata(renderCanonicalResource(sd), sd);
Sheet sheet = wb.createSheet("Elements");
Row headerRow = sheet.createRow(0);
for (int i = 0; i < titles.length; i++) {
addCell(headerRow, i, titles[i], styles.get("header"));
}
int i = titles.length - 1;
for (StructureDefinitionMappingComponent map : sd.getMapping()) {
i++;
addCell(headerRow, i, "Mapping: " + map.getName(), styles.get("header"));
}
for (ElementDefinition child : sd.getSnapshot().getElement()) {
processElement(sheet, sd, child);
}
configureSheet(sheet, sd);
return this;
}
private void addStructureDefinitionMetadata(Sheet sheet, StructureDefinition sd) {
for (Coding k : sd.getKeyword()) {
addMetadataRow(sheet, "Keyword", dr.display(k));
}
addMetadataRow(sheet, "FHIR Version", sd.getFhirVersionElement().asStringValue());
addMetadataRow(sheet, "Kind", sd.getKindElement().asStringValue());
addMetadataRow(sheet, "Type", sd.getType());
addMetadataRow(sheet, "Base Definition", sd.getBaseDefinition());
addMetadataRow(sheet, "Abstract", sd.getAbstractElement().asStringValue());
addMetadataRow(sheet, "Derivation", sd.getDerivationElement().asStringValue());
for (StructureDefinitionContextComponent k : sd.getContext()) {
addMetadataRow(sheet, "Context", k.getTypeElement().asStringValue()+":"+k.getExpression());
}
for (StringType k : sd.getContextInvariant()) {
addMetadataRow(sheet, "Context Inv.", k.getValue());
}
}
public void processElement(Sheet sheet, StructureDefinition sd, ElementDefinition ed) throws Exception {
Row row = sheet.createRow(sheet.getLastRowNum()+1);
int i = 0;
addCell(row, i++, ed.getPath(), styles.get("body"));
addCell(row, i++, ed.getSliceName());
addCell(row, i++, itemList(ed.getAlias()));
addCell(row, i++, ed.getLabel());
addCell(row, i++, ed.getMin());
addCell(row, i++, ed.getMax());
addCell(row, i++, ed.getMustSupport() ? "Y" : "");
addCell(row, i++, ed.getIsModifier() ? "Y" : "");
addCell(row, i++, ed.getIsSummary() ? "Y" : "");
addCell(row, i++, itemList(ed.getType()));
addCell(row, i++, ed.getShort());
addCell(row, i++, ed.getDefinition());
addCell(row, i++, ed.getComment());
addCell(row, i++, ed.getRequirements());
addCell(row, i++, ed.getDefaultValue()!=null ? renderType(ed.getDefaultValue()) : "");
addCell(row, i++, ed.getMeaningWhenMissing());
addCell(row, i++, ed.hasFixed() ? renderType(ed.getFixed()) : "");
addCell(row, i++, ed.hasPattern() ? renderType(ed.getPattern()) : "");
addCell(row, i++, ed.hasExample() ? renderType(ed.getExample().get(0).getValue()) : ""); // todo...?
addCell(row, i++, ed.hasMinValue() ? renderType(ed.getMinValue()) : "");
addCell(row, i++, ed.hasMaxValue() ? renderType(ed.getMaxValue()) : "");
addCell(row, i++, (ed.hasMaxLength() ? Integer.toString(ed.getMaxLength()) : ""));
if (ed.hasBinding()) {
addCell(row, i++, ed.getBinding().getStrength()!=null ? ed.getBinding().getStrength().toCode() : "");
addCell(row, i++, ed.getBinding().getDescription());
if (ed.getBinding().getValueSet()==null)
addCell(row, i++, "");
else
addCell(row, i++, ed.getBinding().getValueSet());
} else {
addCell(row, i++, "");
addCell(row, i++, "");
addCell(row, i++, "");
}
addCell(row, i++, itemList(ed.getCode()));
if (ed.hasSlicing()) {
addCell(row, i++, itemList(ed.getSlicing().getDiscriminator()));
addCell(row, i++, ed.getSlicing().getDescription());
addCell(row, i++, ed.getSlicing().getOrdered());
addCell(row, i++, ed.getSlicing().getRules()!=null ? ed.getSlicing().getRules().toCode() : "");
} else {
addCell(row, i++, "");
addCell(row, i++, "");
addCell(row, i++, "");
addCell(row, i++, "");
}
if (ed.getBase()!=null) {
addCell(row, i++, ed.getBase().getPath());
addCell(row, i++, ed.getBase().getMin());
addCell(row, i++, ed.getBase().getMax());
} else {
addCell(row, i++, "");
addCell(row, i++, "");
addCell(row, i++, "");
}
addCell(row, i++, itemList(ed.getCondition()));
addCell(row, i++, itemList(ed.getConstraint()));
for (StructureDefinitionMappingComponent mapKey : sd.getMapping()) {
String mapString = "";
for (ElementDefinitionMappingComponent map : ed.getMapping()) {
if (map.getIdentity().equals(mapKey.getIdentity()))
mapString = map.getMap();
}
addCell(row, i++, mapString);
}
}
private String itemList(List l) {
StringBuilder s = new StringBuilder();
for (int i =0; i< l.size(); i++) {
Object o = l.get(i);
String val = "";
if (o instanceof StringType) {
val = ((StringType)o).getValue();
} else if (o instanceof UriType) {
val = ((UriType)o).getValue();
} else if (o instanceof IdType) {
val = ((IdType)o).getValue();
} else if (o instanceof Enumeration<?>) {
val = o.toString();
} else if (o instanceof TypeRefComponent) {
TypeRefComponent t = (TypeRefComponent)o;
val = t.getWorkingCode();
if (val == null)
val = "";
if (val.startsWith("http://hl7.org/fhir/StructureDefinition/"))
val = val.substring(40);
if (t.hasTargetProfile())
val = val+ "(" + canonicalList(t.getTargetProfile()) + ")";
if (t.hasProfile())
val = val + " {" + canonicalList(t.getProfile()) + "}";
if (t.hasAggregation())
val = val + " <<" + aggList(t.getAggregation()) + ">>";
} else if (o instanceof Coding) {
Coding t = (Coding)o;
val = (t.getSystem()==null ? "" : t.getSystem()) + (t.getCode()==null ? "" : "#" + t.getCode()) + (t.getDisplay()==null ? "" : " (" + t.getDisplay() + ")");
} else if (o instanceof ElementDefinitionConstraintComponent) {
ElementDefinitionConstraintComponent c = (ElementDefinitionConstraintComponent)o;
val = c.getKey() + ":" + c.getHuman() + " {" + c.getExpression() + "}";
} else if (o instanceof ElementDefinitionSlicingDiscriminatorComponent) {
ElementDefinitionSlicingDiscriminatorComponent c = (ElementDefinitionSlicingDiscriminatorComponent)o;
val = c.getType().toCode() + ":" + c.getPath() + "}";
} else {
val = o.toString();
val = val.substring(val.indexOf("[")+1);
val = val.substring(0, val.indexOf("]"));
}
s = s.append(val);
if (i == 0)
s.append("\n");
}
return s.toString();
}
private String aggList(List<org.hl7.fhir.r5.model.Enumeration<AggregationMode>> list) {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
for (org.hl7.fhir.r5.model.Enumeration<AggregationMode> c : list)
b.append(c.getValue().toCode());
return b.toString();
}
private String canonicalList(List<CanonicalType> list) {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder("|");
for (CanonicalType c : list) {
String v = c.getValue();
if (v.startsWith("http://hl7.org/fhir/StructureDefinition/"))
v = v.substring(40);
b.append(v);
}
return b.toString();
}
private String renderType(DataType value) throws Exception {
if (value == null)
return "";
if (value.isPrimitive())
return value.primitiveValue();
String s = null;
ByteArrayOutputStream bs = new ByteArrayOutputStream();
if (asXml) {
xml.setOutputStyle(OutputStyle.PRETTY);
xml.compose(bs, "", value);
bs.close();
s = bs.toString();
s = s.substring(s.indexOf("\n")+2);
} else {
json.setOutputStyle(OutputStyle.PRETTY);
json.compose(bs, value, "");
bs.close();
s = bs.toString();
}
return s;
}
public void configureSheet(Sheet sheet, StructureDefinition sd) throws IOException {
for (int i=0; i<34; i++) {
sheet.autoSizeColumn(i);
}
sheet.setColumnHidden(2, true);
sheet.setColumnHidden(3, true);
sheet.setColumnHidden(30, true);
sheet.setColumnHidden(31, true);
sheet.setColumnHidden(32, true);
sheet.setColumnWidth(9, columnPixels(20));
sheet.setColumnWidth(11, columnPixels(100));
sheet.setColumnWidth(12, columnPixels(100));
sheet.setColumnWidth(13, columnPixels(100));
sheet.setColumnWidth(15, columnPixels(20));
sheet.setColumnWidth(16, columnPixels(20));
sheet.setColumnWidth(17, columnPixels(20));
sheet.setColumnWidth(18, columnPixels(20));
sheet.setColumnWidth(34, columnPixels(100));
int i = titles.length - 1;
for (StructureDefinitionMappingComponent map : sd.getMapping()) {
i++;
sheet.setColumnWidth(i, columnPixels(50));
sheet.autoSizeColumn(i);
// sheet.setColumnHidden(i, true);
}
sheet.createFreezePane(2,1);
if (hideMustSupportFalse) {
SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
String address = "A2:AI" + Math.max(Integer.valueOf(sheet.getLastRowNum()), 2);
CellRangeAddress[] regions = {
CellRangeAddress.valueOf(address)
};
ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule("$G2<>\"Y\"");
PatternFormatting fill1 = rule1.createPatternFormatting();
fill1.setFillBackgroundColor(IndexedColors.GREY_25_PERCENT.index);
fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
ConditionalFormattingRule rule2 = sheetCF.createConditionalFormattingRule("$Q2<>\"\"");
FontFormatting font = rule2.createFontFormatting();
font.setFontColorIndex(IndexedColors.GREY_25_PERCENT.index);
font.setFontStyle(true, false);
sheetCF.addConditionalFormatting(regions, rule1, rule2);
sheet.setAutoFilter(new CellRangeAddress(0,sheet.getLastRowNum(), 0, titles.length+sd.getMapping().size() - 1));
XSSFSheet xSheet = (XSSFSheet)sheet;
CTAutoFilter sheetFilter = xSheet.getCTWorksheet().getAutoFilter();
CTFilterColumn filterColumn1 = sheetFilter.addNewFilterColumn();
filterColumn1.setColId(6);
CTCustomFilters filters = filterColumn1.addNewCustomFilters();
CTCustomFilter filter1 = filters.addNewCustomFilter();
filter1.setOperator(STFilterOperator.NOT_EQUAL);
filter1.setVal(" ");
CTFilterColumn filterColumn2 = sheetFilter.addNewFilterColumn();
filterColumn2.setColId(26);
CTFilters filters2 = filterColumn2.addNewFilters();
filters2.setBlank(true);
// We have to apply the filter ourselves by hiding the rows:
for (Row row : sheet) {
if (row.getRowNum()>0 && (!row.getCell(6).getStringCellValue().equals("Y") || !row.getCell(26).getStringCellValue().isEmpty())) {
((XSSFRow) row).getCTRow().setHidden(true);
}
}
}
sheet.setActiveCell(new CellAddress(sheet.getRow(1).getCell(0)));
}
}

View File

@ -0,0 +1,168 @@
package org.hl7.fhir.r5.renderers.spreadsheets;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionMappingComponent;
import org.hl7.fhir.utilities.i18n.I18nConstants;
public class ValueSetSpreadsheetGenerator extends CanonicalSpreadsheetGenerator {
public ValueSetSpreadsheetGenerator(IWorkerContext context) {
super(context);
}
public boolean canGenerate(ValueSet vs) {
return true;
}
public ValueSetSpreadsheetGenerator renderValueSet(ValueSet vs) throws IOException {
if (vs == null) {
System.out.println("no valueset!");
}
addValueSetMetadata(renderCanonicalResource(vs), vs);
for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
genInclude(vs, inc, "Include");
}
for (ConceptSetComponent exc : vs.getCompose().getExclude()) {
genInclude(vs, exc, "Exclude");
}
if (vs.hasExpansion()) {
if (vs.getExpansion().hasParameter()) {
genExpansionParams(vs.getExpansion().getParameter());
}
genExpansion(vs.getExpansion().getContains());
}
return this;
}
private void addValueSetMetadata(Sheet sheet, ValueSet vs) {
addMetadataRow(sheet, "Immutable", vs.getImmutableElement().toString());
}
private void genExpansionParams(List<ValueSetExpansionParameterComponent> params) {
Sheet sheet = wb.createSheet("Expansion Parameters");
addHeaders(sheet, "Parameter", "Value");
for (ValueSetExpansionParameterComponent p : params) {
addRow(sheet, p.getName(), dr.display(p.getValue()));
}
}
private void genExpansion(List<ValueSetExpansionContainsComponent> list) {
Sheet sheet = wb.createSheet("Expansion");
addHeaders(sheet, "Level", "System", "version", "Code", "Display", "Abstract", "Inactive");
genExpansionEntry(1, list, sheet);
}
public void genExpansionEntry(int level, List<ValueSetExpansionContainsComponent> list, Sheet sheet) {
for (ValueSetExpansionContainsComponent p : list) {
addRow(sheet, Integer.toString(level), p.getSystem(), p.getVersion(), p.getCode(), p.getDisplay(), bool(p.getAbstract()), bool(p.getInactive()));
if (p.hasContains()) {
genExpansionEntry(level + 1, p.getContains(), sheet);
}
}
}
private String bool(boolean value) {
return value ? "" : "false";
}
private void genInclude(ValueSet vs, ConceptSetComponent inc, String mode) {
if (inc.hasSystem()) {
genIncludeSystem(vs, inc, mode);
} else {
genIncludeValueSets(vs, inc, mode);
}
// String subname = inc.hasSystem() ? : "ValueSets";
//
//
// Row headerRow = sheet.createRow(0);
// for (int i = 0; i < titles.length; i++) {
// addCell(headerRow, i, titles[i], styles.get("header"));
// }
// int i = titles.length - 1;
// for (StructureDefinitionMappingComponent map : sd.getMapping()) {
// i++;
// addCell(headerRow, i, "Mapping: " + map.getName(), styles.get("header"));
// }
//
// for (ElementDefinition child : sd.getSnapshot().getElement()) {
// processElement(sheet, sd, child);
// }
// configureSheet(sheet, sd);
}
private void genIncludeValueSets(ValueSet vs, ConceptSetComponent inc, String mode) {
Sheet sheet = wb.createSheet(mode+" ValueSets");
addValueSets(sheet, inc.getValueSet());
configureSheet(sheet);
}
private void genIncludeSystem(ValueSet vs, ConceptSetComponent inc, String mode) {
Sheet sheet = wb.createSheet(mode+" from "+dr.displaySystem(inc.getSystem()));
if (inc.hasValueSet()) {
addValueSets(sheet, inc.getValueSet());
}
if (inc.hasFilter()) {
addFilters(sheet, inc.getFilter());
}
if (inc.hasConcept()) {
addConcepts(sheet, inc.getConcept());
}
if (!inc.hasConcept() && !inc.hasFilter()) {
addAllCodes(sheet);
}
addRow(sheet, "", "");
addRow(sheet, "System URI", inc.getSystem());
configureSheet(sheet);
}
private void addAllCodes(Sheet sheet) {
addHeaders(sheet, "Codes");
addRow(sheet, "All codes");
}
private void addValueSets(Sheet sheet, List<CanonicalType> valueSets) {
addHeaders(sheet, "ValueSet URL");
for (CanonicalType u : valueSets) {
addRow(sheet, u.getValue());
}
}
private void configureSheet(Sheet sheet) {
sheet.setColumnWidth(0, columnPixels(30));
sheet.setColumnWidth(1, columnPixels(40));
sheet.setColumnWidth(1, columnPixels(50));
}
private void addConcepts(Sheet sheet, List<ConceptReferenceComponent> concepts) {
addHeaders(sheet, "Concept", "Description"); // todo: designations
for (ConceptReferenceComponent cd : concepts) {
addRow(sheet, cd.getCode(), cd.getDisplay());
}
}
private void addFilters(Sheet sheet, List<ConceptSetFilterComponent> filters) {
addHeaders(sheet, "Property", "Operation", "Value");
for (ConceptSetFilterComponent f : filters) {
addRow(sheet, f.getProperty(), f.getOpElement().asStringValue(), f.getValue());
}
}
}