Add path and message tracking to element model

This commit is contained in:
Grahame Grieve 2021-06-23 20:35:15 +10:00
parent 91de7ec65b
commit a2c6dd6af1
4 changed files with 474 additions and 407 deletions

View File

@ -55,6 +55,7 @@ import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.utilities.ElementDecoration;
import org.hl7.fhir.utilities.ElementDecoration.DecorationType;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
@ -102,6 +103,8 @@ public class Element extends Base {
private String explicitType; // for xsi:type attribute
private Element parentForValidator;
private boolean hasParentForValidator;
private String path;
private List<ValidationMessage> messages;
public Element(String name) {
super();
@ -706,6 +709,13 @@ public class Element extends Base {
return property.isList();
}
public boolean isBaseList() {
if (elementProperty != null)
return elementProperty.isBaseList();
else
return property.isBaseList();
}
@Override
public String[] getTypesForProperty(int hash, String name) throws FHIRException {
Property p = property.getChildSimpleName(this.name, name);
@ -938,6 +948,29 @@ public class Element extends Base {
property = null;
elementProperty = null;
xhtml = null;
path = null;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public void addMessage(ValidationMessage vm) {
if (messages == null) {
messages = new ArrayList<>();
}
messages.add(vm);
}
public boolean hasMessages() {
return messages != null && !messages.isEmpty();
}
public List<ValidationMessage> getMessages() {
return messages;
}
}

View File

@ -98,6 +98,7 @@ public class JsonParser extends ParserBase {
return null;
Element result = new Element(type, new Property(context, sd.getSnapshot().getElement().get(0), sd, this.profileUtilities));
result.setPath(type);
checkObject(obj, path);
result.setType(type);
parseChildren(path, obj, result, true);
@ -123,7 +124,7 @@ public class JsonParser extends ParserBase {
return parse(obj);
} else {
JsonObject obj = JsonTrackingParser.parse(source, null); // (JsonObject) new com.google.gson.JsonParser().parse(source);
// assert (map.containsKey(obj));
// assert (map.containsKey(obj));
return parse(obj);
}
}
@ -150,6 +151,7 @@ public class JsonParser extends ParserBase {
checkObject(object, path);
result.markLocation(line(object), col(object));
result.setType(name);
result.setPath(result.fhirType());
parseChildren(path, object, result, true);
result.numberChildren();
return result;
@ -215,6 +217,7 @@ public class JsonParser extends ParserBase {
private void parseChildComplex(String path, JsonObject object, Element element, Set<String> processed, Property property, String name) throws FHIRException {
processed.add(name);
String npath = path+"."+property.getName();
String fpath = element.getPath()+"."+property.getName();
JsonElement e = object.get(name);
if (property.isList() && (e instanceof JsonArray)) {
JsonArray arr = (JsonArray) e;
@ -223,14 +226,14 @@ public class JsonParser extends ParserBase {
}
int c = 0;
for (JsonElement am : arr) {
parseChildComplexInstance(npath+"["+c+"]", object, element, property, name, am);
parseChildComplexInstance(npath+"["+c+"]", fpath+"["+c+"]", object, element, property, name, am);
c++;
}
} else {
if (property.isList()) {
logError(line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_ARRAY_NOT_, describeType(e), name, path), IssueSeverity.ERROR);
}
parseChildComplexInstance(npath, object, element, property, name, e);
parseChildComplexInstance(npath, fpath, object, element, property, name, e);
}
}
@ -246,10 +249,11 @@ public class JsonParser extends ParserBase {
return null;
}
private void parseChildComplexInstance(String npath, JsonObject object, Element element, Property property, String name, JsonElement e) throws FHIRException {
private void parseChildComplexInstance(String npath, String fpath, JsonObject object, Element element, Property property, String name, JsonElement e) throws FHIRException {
if (e instanceof JsonObject) {
JsonObject child = (JsonObject) e;
Element n = new Element(name, property).markLocation(line(child), col(child));
n.setPath(fpath);
checkObject(child, npath);
element.getChildren().add(n);
if (property.isResource())
@ -275,6 +279,7 @@ public class JsonParser extends ParserBase {
private void parseChildPrimitive(JsonObject object, Element element, Set<String> processed, Property property, String path, String name) throws FHIRException {
String npath = path+"."+property.getName();
String fpath = element.getPath()+"."+property.getName();
processed.add(name);
processed.add("_"+name);
JsonElement main = object.has(name) ? object.get(name) : null;
@ -296,11 +301,11 @@ public class JsonParser extends ParserBase {
for (int i = 0; i < Math.max(arrC(arr1), arrC(arr2)); i++) {
JsonElement m = arrI(arr1, i);
JsonElement f = arrI(arr2, i);
parseChildPrimitiveInstance(element, property, name, npath, m, f);
parseChildPrimitiveInstance(element, property, name, npath, fpath, m, f);
}
}
} else {
parseChildPrimitiveInstance(element, property, name, npath, main, fork);
parseChildPrimitiveInstance(element, property, name, npath, fpath, main, fork);
}
}
}
@ -313,8 +318,7 @@ public class JsonParser extends ParserBase {
return arr == null ? 0 : arr.size();
}
private void parseChildPrimitiveInstance(Element element, Property property, String name, String npath,
JsonElement main, JsonElement fork) throws FHIRException {
private void parseChildPrimitiveInstance(Element element, Property property, String name, String npath, String fpath, JsonElement main, JsonElement fork) throws FHIRException {
if (main != null && !(main instanceof JsonPrimitive))
logError(line(main), col(main), npath, IssueType.INVALID, context.formatMessage(
I18nConstants.THIS_PROPERTY_MUST_BE_AN_SIMPLE_VALUE_NOT_, describe(main), name, npath), IssueSeverity.ERROR);
@ -322,6 +326,7 @@ public class JsonParser extends ParserBase {
logError(line(fork), col(fork), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_OBJECT_NOT_, describe(fork), name, npath), IssueSeverity.ERROR);
else {
Element n = new Element(name, property).markLocation(line(main != null ? main : fork), col(main != null ? main : fork));
n.setPath(fpath);
element.getChildren().add(n);
if (main != null) {
JsonPrimitive p = (JsonPrimitive) main;

View File

@ -232,6 +232,10 @@ public class Property {
return !"1".equals(definition.getMax());
}
public boolean isBaseList() {
return !"1".equals(definition.getBase().getMax());
}
public String getScopedPropertyName() {
return definition.getBase().getPath();
}

View File

@ -203,6 +203,7 @@ public class XmlParser extends ParserBase {
return null;
Element result = new Element(element.getLocalName(), new Property(context, sd.getSnapshot().getElement().get(0), sd));
result.setPath(element.getLocalName());
checkElement(element, path, result.getProperty());
result.markLocation(line(element), col(element));
result.setType(element.getLocalName());
@ -262,6 +263,7 @@ public class XmlParser extends ParserBase {
public Element parse(org.w3c.dom.Element base, String type) throws Exception {
StructureDefinition sd = getDefinition(0, 0, FormatUtilities.FHIR_NS, type);
Element result = new Element(base.getLocalName(), new Property(context, sd.getSnapshot().getElement().get(0), sd));
result.setPath(base.getLocalName());
String path = "/"+pathPrefix(base.getNamespaceURI())+base.getLocalName();
checkElement(base, path, result.getProperty());
result.setType(base.getLocalName());
@ -283,13 +285,18 @@ public class XmlParser extends ParserBase {
if (property != null) {
if ("ED.data[x]".equals(property.getDefinition().getId()) || (property.getDefinition()!=null && property.getDefinition().getBase()!=null && "ED.data[x]".equals(property.getDefinition().getBase().getPath()))) {
if ("B64".equals(node.getAttribute("representation"))) {
element.getChildren().add(new Element("dataBase64Binary", property, "base64Binary", text).markLocation(line, col));
Element n = new Element("dataBase64Binary", property, "base64Binary", text).markLocation(line, col);
n.setPath(element.getPath()+"."+property.getName());
element.getChildren().add(n);
} else {
element.getChildren().add(new Element("dataString", property, "string", text).markLocation(line, col));
Element n = new Element("dataString", property, "string", text).markLocation(line, col);
n.setPath(element.getPath()+"."+property.getName());
element.getChildren().add(n);
}
} else {
element.getChildren().add(
new Element(property.getName(), property, property.getType(), text).markLocation(line, col));
Element n = new Element(property.getName(), property, property.getType(), text).markLocation(line, col);
n.setPath(element.getPath()+"."+property.getName());
element.getChildren().add(n);
}
}
else {
@ -325,8 +332,11 @@ public class XmlParser extends ParserBase {
av = convertForDateFormatFromExternal(ToolingExtensions.readStringExtension(property.getDefinition(), "http://www.healthintersections.com.au/fhir/StructureDefinition/elementdefinition-dateformat"), av);
if (property.getName().equals("value") && element.isPrimitive())
element.setValue(av);
else
element.getChildren().add(new Element(property.getName(), property, property.getType(), av).markLocation(line, col));
else {
Element n = new Element(property.getName(), property, property.getType(), av).markLocation(line, col);
n.setPath(element.getPath()+"."+property.getName());
element.getChildren().add(n);
}
} else {
boolean ok = false;
if (FormatUtilities.FHIR_NS.equals(node.getNamespaceURI())) {
@ -342,21 +352,36 @@ public class XmlParser extends ParserBase {
}
}
String lastName = null;
int repeatCount = 0;
Node child = node.getFirstChild();
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++;
} else {
lastName = property.getName();
repeatCount = 0;
}
if (!property.isChoice() && "xhtml".equals(property.getType())) {
XhtmlNode xhtml;
if (property.getDefinition().hasRepresentation(PropertyRepresentation.CDATEXT))
xhtml = new CDANarrativeFormat().convert((org.w3c.dom.Element) child);
else
xhtml = new XhtmlParser().setValidatorMode(true).parseHtmlNode((org.w3c.dom.Element) child);
element.getChildren().add(new Element(property.getName(), property, "xhtml", new XhtmlComposer(XhtmlComposer.XML, false).compose(xhtml)).setXhtml(xhtml).markLocation(line(child), col(child)));
Element n = new Element(property.getName(), property, "xhtml", new XhtmlComposer(XhtmlComposer.XML, false).compose(xhtml)).setXhtml(xhtml).markLocation(line(child), col(child));
n.setPath(element.getPath()+"."+property.getName());
element.getChildren().add(n);
} else {
String npath = path+"/"+pathPrefix(child.getNamespaceURI())+child.getLocalName();
Element n = new Element(child.getLocalName(), property).markLocation(line(child), col(child));
if (property.isList()) {
n.setPath(element.getPath()+"."+property.getName()+"["+repeatCount+"]");
} else {
n.setPath(element.getPath()+"."+property.getName());
}
checkElement((org.w3c.dom.Element) child, npath, n.getProperty());
boolean ok = true;
if (property.isChoice()) {