diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java index a79da099c..f4717fce2 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java @@ -304,8 +304,10 @@ public class XmlParser extends ParserBase { // this parsing routine retains the original order in a the XML file, to support validation reapComments(node, element); List properties = element.getProperty().getChildProperties(element.getName(), XMLUtil.getXsiType(node)); + Property cgProp = getChoiceGroupProp(properties); + Property mtProp = cgProp == null ? null : getTextProp(cgProp.getChildProperties(null, null)); - String text = XMLUtil.getDirectText(node).trim(); + String text = mtProp == null ? XMLUtil.getDirectText(node).trim() : null; int line = line(node, false); int col = col(node, false); if (!Utilities.noString(text)) { @@ -396,6 +398,7 @@ public class XmlParser extends ParserBase { while (child != null) { if (child.getNodeType() == Node.ELEMENT_NODE) { Property property = getElementProp(properties, child.getLocalName(), child.getNamespaceURI()); + if (property != null) { if (property.getName().equals(lastName)) { repeatCount++; @@ -462,9 +465,57 @@ public class XmlParser extends ParserBase { } } } else { - logError(errors, ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNDEFINED_ELEMENT_, child.getLocalName(), path), IssueSeverity.ERROR); + if (cgProp != null) { + property = getElementProp(cgProp.getChildProperties(null, null), child.getLocalName(), child.getNamespaceURI()); + if (property != null) { + if (cgProp.getName().equals(lastName)) { + repeatCount++; + } else { + lastName = cgProp.getName(); + repeatCount = 0; + } + + String npath = path+"/"+pathPrefix(cgProp.getXmlNamespace())+cgProp.getName(); + String name = cgProp.getName(); + Element cgn = new Element(cgProp.getName(), cgProp).setFormat(FhirFormat.XML); + cgn.setPath(element.getPath()+"."+cgProp.getName()+"["+repeatCount+"]"); + element.getChildren().add(cgn); + + npath = npath+"/"+pathPrefix(child.getNamespaceURI())+child.getLocalName(); + name = child.getLocalName(); + Element n = new Element(name, property).markLocation(line(child, false), col(child, false)).setFormat(FhirFormat.XML); + cgn.getChildren().add(n); + n.setPath(element.getPath()+"."+property.getName()); + checkElement(errors, (org.w3c.dom.Element) child, npath, n.getProperty()); + parseChildren(errors, npath, (org.w3c.dom.Element) child, n); + } + } + if (property == null) { + logError(errors, ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNDEFINED_ELEMENT_, child.getLocalName(), path), IssueSeverity.ERROR); + } } - } else if (child.getNodeType() == Node.CDATA_SECTION_NODE){ + } else if (child.getNodeType() == Node.TEXT_NODE && !Utilities.noString(child.getTextContent().trim()) && mtProp != null) { + if (cgProp.getName().equals(lastName)) { + repeatCount++; + } else { + lastName = cgProp.getName(); + repeatCount = 0; + } + + String npath = path+"/"+pathPrefix(cgProp.getXmlNamespace())+cgProp.getName(); + String name = cgProp.getName(); + Element cgn = new Element(cgProp.getName(), cgProp).setFormat(FhirFormat.XML); + cgn.setPath(element.getPath()+"."+cgProp.getName()+"["+repeatCount+"]"); + element.getChildren().add(cgn); + + npath = npath+"/text()"; + name = mtProp.getName(); + Element n = new Element(name, mtProp, mtProp.getType(), child.getTextContent().trim()).markLocation(line(child, false), col(child, false)).setFormat(FhirFormat.XML); + cgn.getChildren().add(n); + n.setPath(element.getPath()+"."+mtProp.getName()); + + + } else if (child.getNodeType() == Node.CDATA_SECTION_NODE) { logError(errors, ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.CDATA_IS_NOT_ALLOWED), IssueSeverity.ERROR); } else if (!Utilities.existsInList(child.getNodeType(), 3, 8)) { logError(errors, ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.NODE_TYPE__IS_NOT_ALLOWED, Integer.toString(child.getNodeType())), IssueSeverity.ERROR); @@ -473,6 +524,15 @@ public class XmlParser extends ParserBase { } } + private Property getChoiceGroupProp(List properties) { + for (Property p : properties) { + if (p.getDefinition().hasExtension(ToolingExtensions.EXT_ID_CHOICE_GROUP)) { + return p; + } + } + return null; + } + private boolean validAttrValue(String value) { if (version == null) { return true; @@ -515,6 +575,8 @@ public class XmlParser extends ParserBase { return p; } } + + return null; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java index 845dc8314..7b8a4a658 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java @@ -95,69 +95,6 @@ import org.hl7.fhir.utilities.xhtml.XhtmlParser; public class StructureDefinitionRenderer extends ResourceRenderer { - // public class ObligationWrapper { - // - // private Extension ext; - // - // public ObligationWrapper(Extension ext) { - // this.ext = ext; - // } - // - // public boolean hasActor() { - // return ext.hasExtension("actor"); - // } - // - // public boolean hasActor(String id) { - // return ext.hasExtension("actor") && id.equals(ext.getExtensionByUrl("actor").getValue().primitiveValue()); - // } - // - // public Coding getCode() { - // Extension code = ext.getExtensionByUrl("obligation"); - // if (code != null && code.hasValueCoding()) { - // return code.getValueCoding(); - // } - // if (code != null && code.hasValueCodeType()) { - // return new Coding().setSystem("http://hl7.org/fhir/tools/CodeSystem/obligation").setCode(code.getValueCodeType().primitiveValue()); - // } - // return null; - // } - // - // public boolean hasFilter() { - // return ext.hasExtension("filter"); - // } - // - // public String getFilter() { - // Extension code = ext.getExtensionByUrl("filter"); - // if (code != null && code.getValue() != null) { - // return code.getValue().primitiveValue(); - // } - // return null; - // } - // - // public boolean hasUsage() { - // return ext.hasExtension("usage"); - // } - // - // public String getFilterDocumentation() { - // Extension code = ext.getExtensionByUrl("filter-desc"); - // if (code != null && code.getValue() != null) { - // return code.getValue().primitiveValue(); - // } - // return null; - // } - // - // public List getUsage() { - // List usage = new ArrayList<>(); - // for (Extension u : ext.getExtensionsByUrl("usage" )) { - // if (u.hasValueUsageContext()) { - // usage.add(u.getValueUsageContext()); - // } - // } - // return usage; - // } - // - // } - public class SourcedElementDefinition { private StructureDefinition profile; private ElementDefinition definition; @@ -1473,6 +1410,11 @@ public class StructureDefinitionRenderer extends ResourceRenderer { c.getPieces().add(gen.new Piece(null, "An ID is not allowed in this context", null)); } } + if (definition.hasExtension(ToolingExtensions.EXT_ID_CHOICE_GROUP)) { + if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } + c.getPieces().add(gen.new Piece(null, translate("sd.table", "Choice Group")+": ", null).addStyle("font-weight:bold")); + c.getPieces().add(gen.new Piece(null, "This is a repeating choice group that does not appear directly in the instance", null)); + } if (definition.hasExtension(ToolingExtensions.EXT_XML_NAME)) { if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } if (definition.hasExtension(ToolingExtensions.EXT_XML_NAMESPACE)) { @@ -3663,6 +3605,11 @@ public class StructureDefinitionRenderer extends ResourceRenderer { tableRow(tbl, "ID Expectation", null, strikethrough, "An ID is not allowed in this context"); } } + + if (d.hasExtension(ToolingExtensions.EXT_ID_CHOICE_GROUP)) { + tableRow(tbl, "Choice Group", null, strikethrough, "This is a repeating choice group that does not appear directly in the instance"); + } + // tooling extensions for formats if (ToolingExtensions.hasExtensions(d, ToolingExtensions.EXT_JSON_EMPTY, ToolingExtensions.EXT_JSON_PROP_KEY, ToolingExtensions.EXT_JSON_NULLABLE, ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_PRIMITIVE_CHOICE)) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java index bdc0cb3f5..042dade65 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java @@ -255,7 +255,7 @@ public class ToolingExtensions { public static final String EXT_OBLIGATION_TOOLS = "http://hl7.org/fhir/tools/StructureDefinition/obligation"; public static final String EXT_OBLIGATION_CORE = "http://hl7.org/fhir/StructureDefinition/obligation"; public static final String EXT_NO_BINDING = "http://hl7.org/fhir/tools/StructureDefinition/no-binding"; - ; + public static final String EXT_ID_CHOICE_GROUP = "http://hl7.org/fhir/tools/StructureDefinition/xml-choice-group"; // specific extension helpers