update JSON parser used by validator to JSON5 parser
This commit is contained in:
parent
363a95bb8a
commit
53fb08ab19
|
@ -37,6 +37,7 @@ import java.io.OutputStream;
|
|||
import java.io.OutputStreamWriter;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
|
@ -54,6 +55,7 @@ import org.hl7.fhir.r5.formats.IParser.OutputStyle;
|
|||
import org.hl7.fhir.r5.formats.JsonCreator;
|
||||
import org.hl7.fhir.r5.formats.JsonCreatorCanonical;
|
||||
import org.hl7.fhir.r5.formats.JsonCreatorGson;
|
||||
import org.hl7.fhir.r5.model.Base;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
|
||||
import org.hl7.fhir.r5.model.Extension;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
|
@ -64,24 +66,22 @@ import org.hl7.fhir.utilities.StringPair;
|
|||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser.LocationData;
|
||||
import org.hl7.fhir.utilities.json.JsonUtilities;
|
||||
import org.hl7.fhir.utilities.json.model.JsonArray;
|
||||
import org.hl7.fhir.utilities.json.model.JsonComment;
|
||||
import org.hl7.fhir.utilities.json.model.JsonElement;
|
||||
import org.hl7.fhir.utilities.json.model.JsonNull;
|
||||
import org.hl7.fhir.utilities.json.model.JsonObject;
|
||||
import org.hl7.fhir.utilities.json.model.JsonPrimitive;
|
||||
import org.hl7.fhir.utilities.json.model.JsonProperty;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonNull;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
public class JsonParser extends ParserBase {
|
||||
|
||||
private JsonCreator json;
|
||||
private Map<JsonElement, LocationData> map;
|
||||
private boolean allowComments;
|
||||
|
||||
private ProfileUtilities profileUtilities;
|
||||
|
@ -100,7 +100,7 @@ public class JsonParser extends ParserBase {
|
|||
}
|
||||
|
||||
public Element parse(String source, String type) throws Exception {
|
||||
JsonObject obj = (JsonObject) new com.google.gson.JsonParser().parse(source);
|
||||
JsonObject obj = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(source, true, true);
|
||||
String path = "/"+type;
|
||||
StructureDefinition sd = getDefinition(-1, -1, type);
|
||||
if (sd == null)
|
||||
|
@ -108,7 +108,7 @@ public class JsonParser extends ParserBase {
|
|||
|
||||
Element result = new Element(type, new Property(context, sd.getSnapshot().getElement().get(0), sd, this.profileUtilities));
|
||||
result.setPath(type);
|
||||
checkObject(obj, path);
|
||||
checkObject(obj, result, path);
|
||||
result.setType(type);
|
||||
parseChildren(path, obj, result, true);
|
||||
result.numberChildren();
|
||||
|
@ -120,37 +120,25 @@ public class JsonParser extends ParserBase {
|
|||
public List<NamedElement> parse(InputStream stream) throws IOException, FHIRException {
|
||||
// if we're parsing at this point, then we're going to use the custom parser
|
||||
List<NamedElement> res = new ArrayList<>();
|
||||
map = new IdentityHashMap<JsonElement, LocationData>();
|
||||
String source = TextFile.streamToString(stream);
|
||||
JsonObject obj = null;
|
||||
if (policy == ValidationPolicy.EVERYTHING) {
|
||||
JsonObject obj = null;
|
||||
try {
|
||||
obj = JsonTrackingParser.parse(source, map, false, allowComments);
|
||||
obj = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(source, true, true);
|
||||
} catch (Exception e) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, -1, -1,context.formatMessage(I18nConstants.DOCUMENT), IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_, e.getMessage()), IssueSeverity.FATAL);
|
||||
return null;
|
||||
}
|
||||
assert (map.containsKey(obj));
|
||||
Element e = parse(obj);
|
||||
if (e != null) {
|
||||
res.add(new NamedElement(null, e));
|
||||
}
|
||||
} else {
|
||||
JsonObject obj = JsonTrackingParser.parse(source, null); // (JsonObject) new com.google.gson.JsonParser().parse(source);
|
||||
// assert (map.containsKey(obj));
|
||||
Element e = parse(obj);
|
||||
if (e != null) {
|
||||
res.add(new NamedElement(null, e));
|
||||
}
|
||||
obj = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(source, true, true);
|
||||
}
|
||||
Element e = parse(obj);
|
||||
if (e != null) {
|
||||
res.add(new NamedElement(null, e));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public Element parse(JsonObject object, Map<JsonElement, LocationData> map) throws FHIRException {
|
||||
this.map = map;
|
||||
return parse(object);
|
||||
}
|
||||
|
||||
public Element parse(JsonObject object) throws FHIRException {
|
||||
StructureDefinition sd = getLogical();
|
||||
String name;
|
||||
|
@ -159,8 +147,11 @@ public class JsonParser extends ParserBase {
|
|||
if (rt == null) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(object), col(object), "$", IssueType.INVALID, context.formatMessage(I18nConstants.UNABLE_TO_FIND_RESOURCETYPE_PROPERTY), IssueSeverity.FATAL);
|
||||
return null;
|
||||
} else if (!rt.isJsonString()) {
|
||||
logError("2022-11-26", line(object), col(object), "$", IssueType.INVALID, context.formatMessage(I18nConstants.RESOURCETYPE_PROPERTY_WRONG_TYPE, rt.type().toName()), IssueSeverity.FATAL);
|
||||
return null;
|
||||
} else {
|
||||
name = rt.getAsString();
|
||||
name = rt.asString();
|
||||
|
||||
sd = getDefinition(line(object), col(object), name);
|
||||
if (sd == null) {
|
||||
|
@ -172,7 +163,7 @@ public class JsonParser extends ParserBase {
|
|||
}
|
||||
String path = name;
|
||||
baseElement = new Element(name, new Property(context, sd.getSnapshot().getElement().get(0), sd, this.profileUtilities));
|
||||
checkObject(object, path);
|
||||
checkObject(object, baseElement, path);
|
||||
baseElement.markLocation(line(object), col(object));
|
||||
baseElement.setType(name);
|
||||
baseElement.setPath(baseElement.fhirType());
|
||||
|
@ -181,17 +172,26 @@ public class JsonParser extends ParserBase {
|
|||
return baseElement;
|
||||
}
|
||||
|
||||
private void checkObject(JsonObject object, String path) throws FHIRFormatError {
|
||||
private void checkObject(JsonObject object, Element b, String path) {
|
||||
checkComments(object, b, path);
|
||||
if (policy == ValidationPolicy.EVERYTHING) {
|
||||
boolean found = false;
|
||||
for (Entry<String, JsonElement> e : object.entrySet()) {
|
||||
// if (!e.getKey().equals("fhir_comments")) {
|
||||
found = true;
|
||||
break;
|
||||
// }
|
||||
}
|
||||
if (!found)
|
||||
if (object.getProperties().size() == 0) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(object), col(object), path, IssueType.INVALID, context.formatMessage(I18nConstants.OBJECT_MUST_HAVE_SOME_CONTENT), IssueSeverity.ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkComments(JsonElement element, Element b, String path) throws FHIRFormatError {
|
||||
if (element.hasComments()) {
|
||||
if (allowComments) {
|
||||
for (JsonComment c : element.getComments()) {
|
||||
b.getFormatCommentsPre().add(c.getContent());
|
||||
}
|
||||
} else {
|
||||
for (JsonComment c : element.getComments()) {
|
||||
logError("2022-11-26", c.getStart().getLine(), c.getStart().getCol(), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMENTS_NOT_ALLOWED), IssueSeverity.ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,43 +199,64 @@ public class JsonParser extends ParserBase {
|
|||
reapComments(object, element);
|
||||
List<Property> properties = element.getProperty().getChildProperties(element.getName(), null);
|
||||
Set<String> processed = new HashSet<String>();
|
||||
if (hasResourceType)
|
||||
if (hasResourceType) {
|
||||
processed.add("resourceType");
|
||||
}
|
||||
Map<String, JsonProperty> recognisedChildren = new HashMap<>();
|
||||
Set<String> unique = new HashSet<>();
|
||||
for (JsonProperty p : object.getProperties()) {
|
||||
if (p.isUnquotedName()) {
|
||||
logError("2022-11-26", line(p.getValue()), col(p.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_PROPERTY_NO_QUOTES, p.getName()), IssueSeverity.ERROR);
|
||||
}
|
||||
if (p.isNoComma()) {
|
||||
logError("2022-11-26", line(p.getValue()), col(p.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_MISSING), IssueSeverity.ERROR);
|
||||
}
|
||||
if (unique.contains(p.getName())) {
|
||||
logError("2022-11-26", line(p.getValue()), col(p.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.DUPLICATE_JSON_PROPERTY, p.getName()), IssueSeverity.ERROR);
|
||||
} else {
|
||||
unique.add(p.getName());
|
||||
recognisedChildren.put(p.getName(), p);
|
||||
}
|
||||
}
|
||||
|
||||
// note that we do not trouble ourselves to maintain the wire format order here - we don't even know what it was anyway
|
||||
// first pass: process the properties
|
||||
for (Property property : properties) {
|
||||
parseChildItem(path, object, element, processed, property);
|
||||
parseChildItem(path, recognisedChildren, element, processed, property);
|
||||
}
|
||||
|
||||
// second pass: check for things not processed
|
||||
if (policy != ValidationPolicy.NONE) {
|
||||
for (Entry<String, JsonElement> e : object.entrySet()) {
|
||||
for (Entry<String, JsonProperty> e : recognisedChildren.entrySet()) {
|
||||
if (!processed.contains(e.getKey())) {
|
||||
StructureDefinition sd = element.getProperty().isLogical() ? new ContextUtilities(context).fetchByJsonName(e.getKey()) : null;
|
||||
if (sd != null) {
|
||||
Property property = new Property(context, sd.getSnapshot().getElementFirstRep(), sd, element.getProperty().getUtils());
|
||||
parseChildItem(path, object, element, null, property);
|
||||
parseChildItem(path, recognisedChildren, element, null, property);
|
||||
} else {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(e.getValue()), col(e.getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_, e.getKey()), IssueSeverity.ERROR);
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_, e.getKey()), IssueSeverity.ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (object.isExtraComma()) {
|
||||
logError("2022-11-26", object.getEnd().getLine(), object.getEnd().getCol(), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Object"), IssueSeverity.ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void parseChildItem(String path, JsonObject object, Element context, Set<String> processed, Property property) {
|
||||
public void parseChildItem(String path, Map<String, JsonProperty> children, Element context, Set<String> processed, Property property) {
|
||||
if (property.isChoice() || property.getDefinition().getPath().endsWith("data[x]")) {
|
||||
if (property.isJsonPrimitiveChoice()) {
|
||||
if (object.has(property.getJsonName())) {
|
||||
JsonElement je = object.get(property.getJsonName());
|
||||
if (children.containsKey(property.getJsonName())) {
|
||||
JsonElement je = children.get(property.getJsonName()).getValue();
|
||||
if (processed != null) processed.add(property.getJsonName());
|
||||
String type = getTypeFromJsonType(je);
|
||||
if (type == null) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(je), col(je), path, IssueType.STRUCTURE, this.context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_TYPE, describeType(je), property.getName(), property.typeSummary()), IssueSeverity.ERROR);
|
||||
} else if (property.hasType(type)) {
|
||||
Property np = new Property(property.getContext(), property.getDefinition(), property.getStructure(), property.getUtils(), type);
|
||||
parseChildPrimitive(object, context, processed, np, path, property.getName());
|
||||
parseChildPrimitive(children, context, processed, np, path, property.getName());
|
||||
} else {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(je), col(je), path, IssueType.STRUCTURE, this.context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_TYPE_WRONG, describeType(je), property.getName(), type, property.typeSummary()), IssueSeverity.ERROR);
|
||||
}
|
||||
|
@ -243,31 +264,31 @@ public class JsonParser extends ParserBase {
|
|||
} else {
|
||||
for (TypeRefComponent type : property.getDefinition().getType()) {
|
||||
String eName = property.getJsonName().substring(0, property.getName().length()-3) + Utilities.capitalize(type.getWorkingCode());
|
||||
if (!isPrimitive(type.getWorkingCode()) && object.has(eName)) {
|
||||
parseChildComplex(path, object, context, processed, property, eName);
|
||||
if (!isPrimitive(type.getWorkingCode()) && children.containsKey(eName)) {
|
||||
parseChildComplex(path, children, context, processed, property, eName);
|
||||
break;
|
||||
} else if (isPrimitive(type.getWorkingCode()) && (object.has(eName) || object.has("_"+eName))) {
|
||||
parseChildPrimitive(object, context, processed, property, path, eName);
|
||||
} else if (isPrimitive(type.getWorkingCode()) && (children.containsKey(eName) || children.containsKey("_"+eName))) {
|
||||
parseChildPrimitive(children, context, processed, property, path, eName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (property.isPrimitive(property.getType(null))) {
|
||||
parseChildPrimitive(object, context, processed, property, path, property.getJsonName());
|
||||
} else if (object.has(property.getJsonName())) {
|
||||
parseChildComplex(path, object, context, processed, property, property.getJsonName());
|
||||
parseChildPrimitive(children, context, processed, property, path, property.getJsonName());
|
||||
} else if (children.containsKey(property.getJsonName())) {
|
||||
parseChildComplex(path, children, context, processed, property, property.getJsonName());
|
||||
}
|
||||
}
|
||||
|
||||
private String getTypeFromJsonType(JsonElement je) {
|
||||
if (je.isJsonPrimitive()) {
|
||||
JsonPrimitive p = je.getAsJsonPrimitive();
|
||||
if (p.isString()) {
|
||||
JsonPrimitive p = je.asJsonPrimitive();
|
||||
if (p.isJsonString()) {
|
||||
return "string";
|
||||
} else if (p.isBoolean()) {
|
||||
} else if (p.isJsonBoolean()) {
|
||||
return "boolean";
|
||||
} else {
|
||||
String s = p.getAsString();
|
||||
String s = p.asString();
|
||||
if (Utilities.isInteger(s)) {
|
||||
return "integer";
|
||||
} else {
|
||||
|
@ -279,15 +300,19 @@ public class JsonParser extends ParserBase {
|
|||
}
|
||||
}
|
||||
|
||||
private void parseChildComplex(String path, JsonObject object, Element element, Set<String> processed, Property property, String name) throws FHIRException {
|
||||
private void parseChildComplex(String path, Map<String, JsonProperty> children, Element element, Set<String> processed, Property property, String name) throws FHIRException {
|
||||
if (processed != null) {
|
||||
processed.add(name);
|
||||
}
|
||||
String npath = path+"."+property.getName();
|
||||
String fpath = element.getPath()+"."+property.getName();
|
||||
JsonElement e = object.get(name);
|
||||
JsonProperty p = children.get(name);
|
||||
JsonElement e = p == null ? null : p.getValue();
|
||||
if (property.isList() && !property.isJsonKeyArray() && (e instanceof JsonArray)) {
|
||||
JsonArray arr = (JsonArray) e;
|
||||
if (arr.isExtraComma()) {
|
||||
logError("2022-11-26", arr.getEnd().getLine(), arr.getEnd().getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Array"), IssueSeverity.ERROR);
|
||||
}
|
||||
if (arr.size() == 0) {
|
||||
if (property.canBeEmpty()) {
|
||||
// nothing
|
||||
|
@ -320,8 +345,18 @@ public class JsonParser extends ParserBase {
|
|||
logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_OBJECT_NOT_, describe(e)), IssueSeverity.ERROR);
|
||||
} else {
|
||||
JsonObject o = (JsonObject) e;
|
||||
if (o.isExtraComma()) {
|
||||
logError("2022-11-26", o.getEnd().getLine(), o.getEnd().getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Object"), IssueSeverity.ERROR);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (Entry<String, JsonElement> pv : o.entrySet()) {
|
||||
Set<String> names = new HashSet<>();
|
||||
for (JsonProperty pv : o.getProperties()) {
|
||||
if (names.contains(pv.getName())) {
|
||||
logError("2022-11-26", line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.DUPLICATE_JSON_PROPERTY_KEY, pv.getName()), IssueSeverity.ERROR);
|
||||
} else {
|
||||
names.add(pv.getName());
|
||||
}
|
||||
// create an array entry
|
||||
String npathArr = path+"."+property.getName()+"["+i+"]";
|
||||
String fpathArr = element.getPath()+"."+property.getName()+"["+i+"]";
|
||||
|
@ -332,9 +367,10 @@ public class JsonParser extends ParserBase {
|
|||
// handle the key
|
||||
String fpathKey = fpathArr+"."+propK.getName();
|
||||
Element nKey = new Element(code, propK).markLocation(line(pv.getValue()), col(pv.getValue()));
|
||||
checkComments(pv.getValue(), n, fpathArr);
|
||||
nKey.setPath(fpathKey);
|
||||
n.getChildren().add(nKey);
|
||||
nKey.setValue(pv.getKey());
|
||||
nKey.setValue(pv.getName());
|
||||
|
||||
|
||||
boolean ok = true;
|
||||
|
@ -418,7 +454,7 @@ public class JsonParser extends ParserBase {
|
|||
JsonObject child = (JsonObject) e;
|
||||
Element n = new Element(name, property).markLocation(line(child), col(child));
|
||||
n.setPath(fpath);
|
||||
checkObject(child, npath);
|
||||
checkObject(child, n, npath);
|
||||
element.getChildren().add(n);
|
||||
if (property.isResource()) {
|
||||
parseResource(npath, child, n, property);
|
||||
|
@ -429,6 +465,7 @@ public class JsonParser extends ParserBase {
|
|||
// we create an element marked as a null element so we know something was present
|
||||
JsonNull child = (JsonNull) e;
|
||||
Element n = new Element(name, property).markLocation(line(child), col(child));
|
||||
checkComments(child, n, fpath);
|
||||
n.setPath(fpath);
|
||||
element.getChildren().add(n);
|
||||
n.setNull(true);
|
||||
|
@ -455,57 +492,51 @@ public class JsonParser extends ParserBase {
|
|||
}
|
||||
|
||||
private String describeType(JsonElement e) {
|
||||
if (e instanceof JsonArray) {
|
||||
return "array";
|
||||
}
|
||||
if (e instanceof JsonObject) {
|
||||
return "object";
|
||||
}
|
||||
if (e instanceof JsonNull) {
|
||||
return "null";
|
||||
}
|
||||
if (e instanceof JsonPrimitive) {
|
||||
JsonPrimitive p = (JsonPrimitive) e;
|
||||
if (p.isString()) {
|
||||
return "string";
|
||||
} else if (p.isBoolean()) {
|
||||
return "boolean";
|
||||
} else if (p.isNumber()) {
|
||||
return "number";
|
||||
}
|
||||
}
|
||||
return "??";
|
||||
return e.type().toName();
|
||||
}
|
||||
|
||||
private void parseChildPrimitive(JsonObject object, Element element, Set<String> processed, Property property, String path, String name) throws FHIRException {
|
||||
private void parseChildPrimitive(Map<String, JsonProperty> children, 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;
|
||||
JsonElement fork = object.has("_"+name) ? object.get("_"+name) : null;
|
||||
JsonProperty main = children.containsKey(name) ? children.get(name) : null;
|
||||
JsonProperty fork = children.containsKey("_"+name) ? children.get("_"+name) : null;
|
||||
if (main != null && main.getValue().isJsonString() && main.isUnquotedValue()) {
|
||||
logError("2022-11-26", line(main.getValue()), col(main.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_PROPERTY_VALUE_NO_QUOTES, main.getName(), main.getValue().asString()), IssueSeverity.ERROR);
|
||||
}
|
||||
if (main != null || fork != null) {
|
||||
if (property.isList()) {
|
||||
boolean ok = true;
|
||||
if (!(main == null || main instanceof JsonArray)) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_ARRAY_NOT_, describe(main), name, path), IssueSeverity.ERROR);
|
||||
if (!(main == null || main.getValue() instanceof JsonArray)) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(main.getValue()), col(main.getValue()), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_ARRAY_NOT_, describe(main.getValue()), name, path), IssueSeverity.ERROR);
|
||||
ok = false;
|
||||
}
|
||||
if (!(fork == null || fork instanceof JsonArray)) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(fork), col(fork), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_BASE_PROPERTY_MUST_BE_AN_ARRAY_NOT_, describe(main), name, path), IssueSeverity.ERROR);
|
||||
if (!(fork == null || fork.getValue() instanceof JsonArray)) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(fork.getValue()), col(fork.getValue()), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_BASE_PROPERTY_MUST_BE_AN_ARRAY_NOT_, describe(main.getValue()), name, path), IssueSeverity.ERROR);
|
||||
ok = false;
|
||||
}
|
||||
if (ok) {
|
||||
JsonArray arr1 = (JsonArray) main;
|
||||
JsonArray arr2 = (JsonArray) fork;
|
||||
JsonArray arr1 = (JsonArray) (main == null ? null : main.getValue());
|
||||
JsonArray arr2 = (JsonArray) (fork == null ? null : fork.getValue());
|
||||
if (arr1 != null && arr1.isExtraComma()) {
|
||||
logError("2022-11-26", arr1.getEnd().getLine(), arr1.getEnd().getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Array"), IssueSeverity.ERROR);
|
||||
}
|
||||
if (arr2 != null && arr2.isExtraComma()) {
|
||||
logError("2022-11-26", arr2.getEnd().getLine(), arr2.getEnd().getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Array"), IssueSeverity.ERROR);
|
||||
}
|
||||
|
||||
for (int i = 0; i < Math.max(arrC(arr1), arrC(arr2)); i++) {
|
||||
JsonElement m = arrI(arr1, i);
|
||||
JsonElement f = arrI(arr2, i);
|
||||
if (m != null && m.isJsonString() && arr1.isUnquoted(i)) {
|
||||
logError("2022-11-26", line(m), col(m), path+"."+name+"["+i+"]", IssueType.INVALID, context.formatMessage(I18nConstants.JSON_PROPERTY_VALUE_NO_QUOTES, "item", m.asString()), IssueSeverity.ERROR);
|
||||
}
|
||||
parseChildPrimitiveInstance(element, property, name, npath, fpath, m, f);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
parseChildPrimitiveInstance(element, property, name, npath, fpath, main, fork);
|
||||
parseChildPrimitiveInstance(element, property, name, npath, fpath, main == null ? null : main.getValue(), fork == null ? null : fork.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -519,23 +550,24 @@ public class JsonParser extends ParserBase {
|
|||
}
|
||||
|
||||
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))
|
||||
if (main != null && !(main.isJsonBoolean() || main.isJsonNumber() || main.isJsonString())) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(main), col(main), npath, IssueType.INVALID, context.formatMessage(
|
||||
I18nConstants.THIS_PROPERTY_MUST_BE_AN_SIMPLE_VALUE_NOT_, describe(main), name, npath), IssueSeverity.ERROR);
|
||||
else if (fork != null && !(fork instanceof JsonObject))
|
||||
} else if (fork != null && !(fork instanceof JsonObject)) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(fork), col(fork), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_OBJECT_NOT_, describe(fork), name, npath), IssueSeverity.ERROR);
|
||||
else {
|
||||
} else {
|
||||
Element n = new Element(name, property).markLocation(line(main != null ? main : fork), col(main != null ? main : fork));
|
||||
if (main != null) {
|
||||
checkComments(main, n, npath);
|
||||
}
|
||||
if (fork != null) {
|
||||
checkComments(fork, n, npath);
|
||||
}
|
||||
n.setPath(fpath);
|
||||
element.getChildren().add(n);
|
||||
if (main != null) {
|
||||
JsonPrimitive p = (JsonPrimitive) main;
|
||||
if (p.isNumber() && p.getAsNumber() instanceof JsonTrackingParser.PresentedBigDecimal) {
|
||||
String rawValue = ((JsonTrackingParser.PresentedBigDecimal) p.getAsNumber()).getPresentation();
|
||||
n.setValue(property.hasImpliedPrefix() ? property.getImpliedPrefix()+rawValue : rawValue);
|
||||
} else {
|
||||
n.setValue(property.hasImpliedPrefix() ? property.getImpliedPrefix()+p.getAsString() : p.getAsString());
|
||||
}
|
||||
n.setValue(property.hasImpliedPrefix() ? property.getImpliedPrefix()+p.asString() : p.asString());
|
||||
if (!n.getProperty().isChoice() && n.getType().equals("xhtml")) {
|
||||
try {
|
||||
XhtmlParser xhtml = new XhtmlParser();
|
||||
|
@ -552,19 +584,20 @@ public class JsonParser extends ParserBase {
|
|||
if (policy == ValidationPolicy.EVERYTHING) {
|
||||
// now we cross-check the primitive format against the stated type
|
||||
if (Utilities.existsInList(n.getType(), "boolean")) {
|
||||
if (!p.isBoolean()) {
|
||||
if (!p.isJsonBoolean()) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_THE_PRIMITIVE_VALUE_MUST_BE_A_BOOLEAN), IssueSeverity.ERROR);
|
||||
}
|
||||
} else if (Utilities.existsInList(n.getType(), "integer", "unsignedInt", "positiveInt", "decimal")) {
|
||||
if (!p.isNumber())
|
||||
if (!p.isJsonNumber())
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_THE_PRIMITIVE_VALUE_MUST_BE_A_NUMBER), IssueSeverity.ERROR);
|
||||
} else if (!p.isString())
|
||||
} else if (!p.isJsonString()) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_THE_PRIMITIVE_VALUE_MUST_BE_A_STRING), IssueSeverity.ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fork != null) {
|
||||
JsonObject child = (JsonObject) fork;
|
||||
checkObject(child, npath);
|
||||
checkObject(child, n, npath);
|
||||
parseChildren(npath, child, n, false);
|
||||
}
|
||||
}
|
||||
|
@ -575,8 +608,10 @@ public class JsonParser extends ParserBase {
|
|||
JsonElement rt = res.get("resourceType");
|
||||
if (rt == null) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(res), col(res), npath, IssueType.INVALID, context.formatMessage(I18nConstants.UNABLE_TO_FIND_RESOURCETYPE_PROPERTY), IssueSeverity.FATAL);
|
||||
} else if (!rt.isJsonString()) {
|
||||
logError("2022-11-26", line(res), col(res), npath, IssueType.INVALID, context.formatMessage(I18nConstants.RESOURCETYPE_PROPERTY_WRONG_TYPE, rt.type().toName()), IssueSeverity.FATAL);
|
||||
} else {
|
||||
String name = rt.getAsString();
|
||||
String name = rt.asString();
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(name, null));
|
||||
if (sd == null) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(res), col(res), npath, IssueType.INVALID, context.formatMessage(I18nConstants.CONTAINED_RESOURCE_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAME_, name), IssueSeverity.FATAL);
|
||||
|
@ -586,29 +621,22 @@ public class JsonParser extends ParserBase {
|
|||
parseChildren(npath, res, parent, true);
|
||||
}
|
||||
}
|
||||
if (res.isExtraComma()) {
|
||||
logError("2022-11-26", res.getEnd().getLine(), res.getEnd().getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Object"), IssueSeverity.ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void reapComments(JsonObject object, Element context) {
|
||||
if (object.has("fhir_comments")) {
|
||||
JsonArray arr = object.getAsJsonArray("fhir_comments");
|
||||
for (JsonElement e : arr) {
|
||||
context.getComments().add(e.getAsString());
|
||||
}
|
||||
}
|
||||
// todo
|
||||
}
|
||||
|
||||
private int line(JsonElement e) {
|
||||
if (map == null|| !map.containsKey(e))
|
||||
return -1;
|
||||
else
|
||||
return map.get(e).getLine();
|
||||
return e.getStart().getLine();
|
||||
}
|
||||
|
||||
private int col(JsonElement e) {
|
||||
if (map == null|| !map.containsKey(e))
|
||||
return -1;
|
||||
else
|
||||
return map.get(e).getCol();
|
||||
return e.getEnd().getCol();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,18 +21,16 @@ import org.hl7.fhir.r5.formats.IParser.OutputStyle;
|
|||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser.LocationData;
|
||||
import org.hl7.fhir.utilities.json.JsonUtilities;
|
||||
import org.hl7.fhir.utilities.json.model.JsonArray;
|
||||
import org.hl7.fhir.utilities.json.model.JsonElement;
|
||||
import org.hl7.fhir.utilities.json.model.JsonElementType;
|
||||
import org.hl7.fhir.utilities.json.model.JsonObject;
|
||||
import org.hl7.fhir.utilities.json.model.JsonPrimitive;
|
||||
import org.hl7.fhir.utilities.json.model.JsonProperty;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
/**
|
||||
* this class is actually a smart health cards validator.
|
||||
* It's going to parse the JWT and assume that it contains
|
||||
|
@ -51,7 +49,6 @@ import com.google.gson.JsonPrimitive;
|
|||
public class SHCParser extends ParserBase {
|
||||
|
||||
private JsonParser jsonParser;
|
||||
private Map<JsonElement, LocationData> map;
|
||||
private List<String> types = new ArrayList<>();
|
||||
|
||||
public SHCParser(IWorkerContext context) {
|
||||
|
@ -65,16 +62,16 @@ public class SHCParser extends ParserBase {
|
|||
List<String> list = new ArrayList<>();
|
||||
String pfx = null;
|
||||
if (src.startsWith("{")) {
|
||||
JsonObject json = JsonTrackingParser.parseJson(src);
|
||||
JsonObject json = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(src);
|
||||
if (checkProperty(json, "$", "verifiableCredential", true, "Array")) {
|
||||
pfx = "verifiableCredential";
|
||||
JsonArray arr = json.getAsJsonArray("verifiableCredential");
|
||||
JsonArray arr = json.getJsonArray("verifiableCredential");
|
||||
int i = 0;
|
||||
for (JsonElement e : arr) {
|
||||
if (!(e instanceof JsonPrimitive)) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), "$.verifiableCredential["+i+"]", IssueType.STRUCTURE, "Wrong Property verifiableCredential in JSON Payload. Expected : String but found "+JsonUtilities.type(e), IssueSeverity.ERROR);
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), "$.verifiableCredential["+i+"]", IssueType.STRUCTURE, "Wrong Property verifiableCredential in JSON Payload. Expected : String but found "+e.type().toName(), IssueSeverity.ERROR);
|
||||
} else {
|
||||
list.add(e.getAsString());
|
||||
list.add(e.asString());
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
@ -95,14 +92,13 @@ public class SHCParser extends ParserBase {
|
|||
logError(ValidationMessage.NO_RULE_DATE, 1, 1, prefix+"JWT", IssueType.INVALID, "Unable to decode JWT token", IssueSeverity.ERROR);
|
||||
return res;
|
||||
}
|
||||
map = jwt.map;
|
||||
|
||||
checkNamedProperties(jwt.getPayload(), prefix+"payload", "iss", "nbf", "vc");
|
||||
checkProperty(jwt.getPayload(), prefix+"payload", "iss", true, "String");
|
||||
logError(ValidationMessage.NO_RULE_DATE, 1, 1, prefix+"JWT", IssueType.INFORMATIONAL, "The FHIR Validator does not check the JWT signature "+
|
||||
"(see https://demo-portals.smarthealth.cards/VerifierPortal.html or https://github.com/smart-on-fhir/health-cards-dev-tools) (Issuer = '"+jwt.getPayload().get("iss").getAsString()+"')", IssueSeverity.INFORMATION);
|
||||
"(see https://demo-portals.smarthealth.cards/VerifierPortal.html or https://github.com/smart-on-fhir/health-cards-dev-tools) (Issuer = '"+jwt.getPayload().asString("iss")+"')", IssueSeverity.INFORMATION);
|
||||
checkProperty(jwt.getPayload(), prefix+"payload", "nbf", true, "Number");
|
||||
JsonObject vc = jwt.getPayload().getAsJsonObject("vc");
|
||||
JsonObject vc = jwt.getPayload().getJsonObject("vc");
|
||||
if (vc == null) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, 1, 1, "JWT", IssueType.STRUCTURE, "Unable to find property 'vc' in the payload", IssueSeverity.ERROR);
|
||||
return res;
|
||||
|
@ -112,13 +108,13 @@ public class SHCParser extends ParserBase {
|
|||
if (!checkProperty(vc, path, "type", true, "Array")) {
|
||||
return res;
|
||||
}
|
||||
JsonArray type = vc.getAsJsonArray("type");
|
||||
JsonArray type = vc.getJsonArray("type");
|
||||
int i = 0;
|
||||
for (JsonElement e : type) {
|
||||
if (!(e instanceof JsonPrimitive)) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), path+".type["+i+"]", IssueType.STRUCTURE, "Wrong Property Type in JSON Payload. Expected : String but found "+JsonUtilities.type(e), IssueSeverity.ERROR);
|
||||
if (e.type() != JsonElementType.STRING) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), path+".type["+i+"]", IssueType.STRUCTURE, "Wrong Property Type in JSON Payload. Expected : String but found "+e.type().toName(), IssueSeverity.ERROR);
|
||||
} else {
|
||||
types.add(e.getAsString());
|
||||
types.add(e.asString());
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
@ -129,21 +125,21 @@ public class SHCParser extends ParserBase {
|
|||
if (!checkProperty(vc, path, "credentialSubject", true, "Object")) {
|
||||
return res;
|
||||
}
|
||||
JsonObject cs = vc.getAsJsonObject("credentialSubject");
|
||||
JsonObject cs = vc.getJsonObject("credentialSubject");
|
||||
path = path+".credentialSubject";
|
||||
if (!checkProperty(cs, path, "fhirVersion", true, "String")) {
|
||||
return res;
|
||||
}
|
||||
JsonElement fv = cs.get("fhirVersion");
|
||||
if (!VersionUtilities.versionsCompatible(context.getVersion(), fv.getAsString())) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(fv), col(fv), path+".fhirVersion", IssueType.STRUCTURE, "Card claims to be of version "+fv.getAsString()+", cannot be validated against version "+context.getVersion(), IssueSeverity.ERROR);
|
||||
if (!VersionUtilities.versionsCompatible(context.getVersion(), fv.asString())) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(fv), col(fv), path+".fhirVersion", IssueType.STRUCTURE, "Card claims to be of version "+fv.asString()+", cannot be validated against version "+context.getVersion(), IssueSeverity.ERROR);
|
||||
return res;
|
||||
}
|
||||
if (!checkProperty(cs, path, "fhirBundle", true, "Object")) {
|
||||
return res;
|
||||
}
|
||||
// ok. all checks passed, we can now validate the bundle
|
||||
Element e = jsonParser.parse(cs.getAsJsonObject("fhirBundle"), map);
|
||||
Element e = jsonParser.parse(cs.getJsonObject("fhirBundle"));
|
||||
if (e != null) {
|
||||
res.add(new NamedElement(path, e));
|
||||
}
|
||||
|
@ -170,7 +166,7 @@ public class SHCParser extends ParserBase {
|
|||
private boolean checkProperty(JsonObject obj, String path, String name, boolean required, String type) {
|
||||
JsonElement e = obj.get(name);
|
||||
if (e != null) {
|
||||
String t = JsonUtilities.type(e);
|
||||
String t = e.type().toName();
|
||||
if (!type.equals(t)) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), path+"."+name, IssueType.STRUCTURE, "Wrong Property Type in JSON Payload. Expected : "+type+" but found "+t, IssueSeverity.ERROR);
|
||||
} else {
|
||||
|
@ -185,25 +181,19 @@ public class SHCParser extends ParserBase {
|
|||
}
|
||||
|
||||
private void checkNamedProperties(JsonObject obj, String path, String... names) {
|
||||
for (Entry<String, JsonElement> e : obj.entrySet()) {
|
||||
if (!Utilities.existsInList(e.getKey(), names)) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(e.getValue()), col(e.getValue()), path+"."+e.getKey(), IssueType.STRUCTURE, "Unknown Property in JSON Payload", IssueSeverity.WARNING);
|
||||
for (JsonProperty e : obj.getProperties()) {
|
||||
if (!Utilities.existsInList(e.getName(), names)) {
|
||||
logError(ValidationMessage.NO_RULE_DATE, line(e.getValue()), col(e.getValue()), path+"."+e.getName(), IssueType.STRUCTURE, "Unknown Property in JSON Payload", IssueSeverity.WARNING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int line(JsonElement e) {
|
||||
if (map == null|| !map.containsKey(e))
|
||||
return -1;
|
||||
else
|
||||
return map.get(e).getLine();
|
||||
return e.getStart().getLine();
|
||||
}
|
||||
|
||||
private int col(JsonElement e) {
|
||||
if (map == null|| !map.containsKey(e))
|
||||
return -1;
|
||||
else
|
||||
return map.get(e).getCol();
|
||||
return e.getStart().getCol();
|
||||
}
|
||||
|
||||
|
||||
|
@ -218,7 +208,6 @@ public class SHCParser extends ParserBase {
|
|||
|
||||
private JsonObject header;
|
||||
private JsonObject payload;
|
||||
public Map<JsonElement, LocationData> map = new HashMap<>();
|
||||
|
||||
public JsonObject getHeader() {
|
||||
return header;
|
||||
|
@ -273,11 +262,11 @@ public class SHCParser extends ParserBase {
|
|||
throw new FHIRException("The input is not a valid base 64 encoded string.", e);
|
||||
}
|
||||
JWT res = new JWT();
|
||||
res.header = JsonTrackingParser.parseJson(headerJson);
|
||||
if ("DEF".equals(JsonUtilities.str(res.header, "zip"))) {
|
||||
res.header = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(headerJson);
|
||||
if ("DEF".equals(res.header.asString("zip"))) {
|
||||
payloadJson = inflate(payloadJson);
|
||||
}
|
||||
res.payload = JsonTrackingParser.parse(TextFile.bytesToString(payloadJson), res.map, true);
|
||||
res.payload = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(TextFile.bytesToString(payloadJson), true);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ package org.hl7.fhir.r5.utils.validation;
|
|||
*/
|
||||
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
|
||||
import org.hl7.fhir.r5.model.Coding;
|
||||
|
@ -38,6 +37,7 @@ import org.hl7.fhir.r5.model.StructureDefinition;
|
|||
import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.CheckDisplayOption;
|
||||
import org.hl7.fhir.r5.utils.validation.constants.IdStatus;
|
||||
import org.hl7.fhir.utilities.json.model.JsonObject;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package org.hl7.fhir.r5.test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.hl7.fhir.r5.test.utils.TestingUtilities;
|
||||
import org.hl7.fhir.utilities.json.model.JsonElement;
|
||||
import org.hl7.fhir.utilities.json.model.JsonObject;
|
||||
import org.hl7.fhir.utilities.json.parser.JsonParser;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class JsonParserTests {
|
||||
|
||||
@Test
|
||||
public void testLocations() throws IOException {
|
||||
String cnt = TestingUtilities.loadTestResource("validator", "slice23", "AuditEvent-ex-FirstSliceProfile.json");
|
||||
JsonObject json = JsonParser.parseObject(cnt);
|
||||
checkLine(json, 1, 1);
|
||||
checkLine(json.get("resourceType"), 2, 19);
|
||||
checkLine(json.get("id"), 3, 9);
|
||||
checkLine(json.get("meta"), 4, 11);
|
||||
checkLine(json.getJsonObject("meta").get("security"), 5, 17);
|
||||
checkLine(json.get("agent"), 15, 12);
|
||||
checkLine(json.getJsonArray("agent").get(0), 16, 5);
|
||||
checkLine(json.getJsonArray("agent").get(0).asJsonObject().get("type"), 17, 15);
|
||||
checkLine(json.getJsonArray("agent").get(0).asJsonObject().get("requestor"), 32, 20);
|
||||
checkLine(json.getJsonArray("agent").get(1), 34, 5);
|
||||
|
||||
checkLine(json.get("type"), 50, 11);
|
||||
}
|
||||
|
||||
private void checkLine(JsonElement e, int line, int col) {
|
||||
Assertions.assertEquals(line, e.getStart().getLine(), "line");
|
||||
Assertions.assertEquals(col, e.getStart().getCol(), "col");
|
||||
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ package org.hl7.fhir.utilities.i18n;
|
|||
|
||||
public class I18nConstants {
|
||||
|
||||
|
||||
public static final String ADDING_WRONG_PATH = "Adding_wrong_path";
|
||||
public static final String ADDING_WRONG_PATH_IN_PROFILE___VS_ = "Adding_wrong_path_in_profile___vs_";
|
||||
public static final String ADDING_WRONG_PATH__OUTCOMEGETPATH___RESULTPATHBASE__ = "Adding_wrong_path__outcomegetPath___resultPathBase__";
|
||||
|
@ -543,6 +542,7 @@ public class I18nConstants {
|
|||
public static final String UNABLE_TO_FIND_ELEMENT__IN_ = "Unable_to_find_element__in_";
|
||||
public static final String UNABLE_TO_FIND_PROFILE__AT_ = "Unable_to_find_profile__at_";
|
||||
public static final String UNABLE_TO_FIND_RESOURCETYPE_PROPERTY = "Unable_to_find_resourceType_property";
|
||||
public static final String RESOURCETYPE_PROPERTY_WRONG_TYPE = "RESOURCETYPE_PROPERTY_WRONG_TYPE";
|
||||
public static final String UNABLE_TO_FIND_RESOURCE__AT__RESOLVING_DISCRIMINATOR__FROM_ = "Unable_to_find_resource__at__resolving_discriminator__from_";
|
||||
public static final String UNABLE_TO_FIND__RESOLVING_DISCRIMINATOR__FROM_ = "Unable_to_find__resolving_discriminator__from_";
|
||||
public static final String UNABLE_TO_HANDLE_SYSTEM__CONCEPT_FILTER_WITH_OP__ = "Unable_to_handle_system__concept_filter_with_op__";
|
||||
|
@ -750,6 +750,13 @@ public class I18nConstants {
|
|||
public static final String XHTML_XHTML_Entity_Illegal = "XHTML_XHTML_Entity_Illegal";
|
||||
public static final String UNABLE_TO_RESOLVE_CONTENT_REFERENCE = "UNABLE_TO_RESOLVE_CONTENT_REFERENCE";
|
||||
public static final String UNABLE_TO_RESOLVE_CONTENT_REFERENCE_IN_THIS_CONTEXT = "UNABLE_TO_RESOLVE_CONTENT_REFERENCE_IN_THIS_CONTEXT";
|
||||
public static final String DUPLICATE_JSON_PROPERTY = "DUPLICATE_JSON_PROPERTY";
|
||||
public static final String DUPLICATE_JSON_PROPERTY_KEY = "DUPLICATE_JSON_PROPERTY_KEY";
|
||||
public static final String JSON_PROPERTY_NO_QUOTES = "JSON_PROPERTY_NO_QUOTES";
|
||||
public static final String JSON_PROPERTY_VALUE_NO_QUOTES = "JSON_PROPERTY_VALUE_NO_QUOTES";
|
||||
public static final String JSON_COMMA_MISSING = "JSON_COMMA_MISSING";
|
||||
public static final String JSON_COMMA_EXTRA = "JSON_COMMA_EXTRA";
|
||||
public static final String JSON_COMMENTS_NOT_ALLOWED = "JSON_COMMENTS_NOT_ALLOWED";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ public class JsonArray extends JsonElement implements Iterable<JsonElement> {
|
|||
private List<JsonElement> items = new ArrayList<>();
|
||||
private List<Boolean> noCommas; // validator use
|
||||
private List<Boolean> unQuoted; // validator use
|
||||
private boolean extraComma; // json5 support
|
||||
|
||||
public List<String> asStrings() {
|
||||
List<String> list = new ArrayList<>();
|
||||
|
@ -36,7 +37,7 @@ public class JsonArray extends JsonElement implements Iterable<JsonElement> {
|
|||
return list;
|
||||
}
|
||||
|
||||
public JsonElementType elementType() {
|
||||
public JsonElementType type() {
|
||||
return JsonElementType.ARRAY;
|
||||
}
|
||||
|
||||
|
@ -125,5 +126,13 @@ public class JsonArray extends JsonElement implements Iterable<JsonElement> {
|
|||
b.append(" ]");
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
public boolean isExtraComma() {
|
||||
return extraComma;
|
||||
}
|
||||
|
||||
public void setExtraComma(boolean extraComma) {
|
||||
this.extraComma = extraComma;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ public class JsonBoolean extends JsonPrimitive {
|
|||
private JsonBoolean() {
|
||||
}
|
||||
|
||||
public JsonElementType elementType() {
|
||||
public JsonElementType type() {
|
||||
return JsonElementType.BOOLEAN;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package org.hl7.fhir.utilities.json.model;
|
||||
|
||||
public class JsonComment {
|
||||
private JsonLocationData start;
|
||||
private JsonLocationData end;
|
||||
private String content;
|
||||
|
||||
public JsonComment(String content, JsonLocationData start, JsonLocationData end) {
|
||||
super();
|
||||
this.content = content;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public JsonLocationData getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public JsonLocationData getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -7,13 +7,13 @@ import org.hl7.fhir.utilities.json.JsonException;
|
|||
|
||||
public abstract class JsonElement {
|
||||
|
||||
private List<String> comments;
|
||||
private List<JsonComment> comments;
|
||||
private JsonLocationData start;
|
||||
private JsonLocationData end;
|
||||
|
||||
public abstract JsonElementType elementType();
|
||||
public abstract JsonElementType type();
|
||||
|
||||
public List<String> getComments() {
|
||||
public List<JsonComment> getComments() {
|
||||
if (comments == null ) {
|
||||
comments = new ArrayList<>();
|
||||
}
|
||||
|
@ -54,11 +54,11 @@ public abstract class JsonElement {
|
|||
protected abstract JsonElement make();
|
||||
|
||||
public boolean isJsonObject() {
|
||||
return elementType() == JsonElementType.OBJECT;
|
||||
return type() == JsonElementType.OBJECT;
|
||||
}
|
||||
|
||||
public boolean isJsonArray() {
|
||||
return elementType() == JsonElementType.ARRAY;
|
||||
return type() == JsonElementType.ARRAY;
|
||||
}
|
||||
|
||||
public boolean isJsonPrimitive() {
|
||||
|
@ -66,19 +66,19 @@ public abstract class JsonElement {
|
|||
}
|
||||
|
||||
public boolean isJsonBoolean() {
|
||||
return elementType() == JsonElementType.BOOLEAN;
|
||||
return type() == JsonElementType.BOOLEAN;
|
||||
}
|
||||
|
||||
public boolean isJsonString() {
|
||||
return elementType() == JsonElementType.STRING;
|
||||
return type() == JsonElementType.STRING;
|
||||
}
|
||||
|
||||
public boolean isJsonNumber() {
|
||||
return elementType() == JsonElementType.NUMBER;
|
||||
return type() == JsonElementType.NUMBER;
|
||||
}
|
||||
|
||||
public boolean isJsonNull() {
|
||||
return elementType() == JsonElementType.NULL;
|
||||
return type() == JsonElementType.NULL;
|
||||
}
|
||||
|
||||
public JsonObject asJsonObject() {
|
||||
|
|
|
@ -2,4 +2,16 @@ package org.hl7.fhir.utilities.json.model;
|
|||
|
||||
public enum JsonElementType {
|
||||
OBJECT, ARRAY, STRING, NUMBER, BOOLEAN, NULL;
|
||||
|
||||
public String toName() {
|
||||
switch (this) {
|
||||
case ARRAY: return "Array";
|
||||
case BOOLEAN: return "Boolean";
|
||||
case NULL: return "Null";
|
||||
case NUMBER: return "Number";
|
||||
case OBJECT: return "Object";
|
||||
case STRING: return "String";
|
||||
default: return "??";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public class JsonLocationData {
|
|||
public void back() {
|
||||
if (col == 1) {
|
||||
line--;
|
||||
line = lastCol;
|
||||
col = lastCol;
|
||||
} else {
|
||||
col--;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package org.hl7.fhir.utilities.json.model;
|
|||
|
||||
public class JsonNull extends JsonPrimitive {
|
||||
|
||||
public JsonElementType elementType() {
|
||||
public JsonElementType type() {
|
||||
return JsonElementType.NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ public class JsonNumber extends JsonPrimitive {
|
|||
private JsonNumber() {
|
||||
}
|
||||
|
||||
public JsonElementType elementType() {
|
||||
public JsonElementType type() {
|
||||
return JsonElementType.NUMBER;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,9 @@ public class JsonObject extends JsonElement {
|
|||
|
||||
private List<JsonProperty> properties = new ArrayList<>();
|
||||
private Map<String, JsonProperty> propMap = new HashMap<>();
|
||||
private boolean extraComma; // json5 support
|
||||
|
||||
public JsonElementType elementType() {
|
||||
public JsonElementType type() {
|
||||
return JsonElementType.OBJECT;
|
||||
}
|
||||
|
||||
|
@ -151,11 +152,11 @@ public class JsonObject extends JsonElement {
|
|||
}
|
||||
|
||||
public boolean hasObject(String name) {
|
||||
return propMap.containsKey(name) && propMap.get(name).getValue().elementType() == JsonElementType.OBJECT;
|
||||
return propMap.containsKey(name) && propMap.get(name).getValue().type() == JsonElementType.OBJECT;
|
||||
}
|
||||
|
||||
public boolean hasArray(String name) {
|
||||
return propMap.containsKey(name) && propMap.get(name).getValue().elementType() == JsonElementType.ARRAY;
|
||||
return propMap.containsKey(name) && propMap.get(name).getValue().type() == JsonElementType.ARRAY;
|
||||
}
|
||||
|
||||
public boolean hasPrimitive(String name) {
|
||||
|
@ -163,19 +164,19 @@ public class JsonObject extends JsonElement {
|
|||
}
|
||||
|
||||
public boolean hasString(String name) {
|
||||
return propMap.containsKey(name) && propMap.get(name).getValue().elementType() == JsonElementType.STRING;
|
||||
return propMap.containsKey(name) && propMap.get(name).getValue().type() == JsonElementType.STRING;
|
||||
}
|
||||
|
||||
public boolean hasNumber(String name) {
|
||||
return propMap.containsKey(name) && propMap.get(name).getValue().elementType() == JsonElementType.NUMBER;
|
||||
return propMap.containsKey(name) && propMap.get(name).getValue().type() == JsonElementType.NUMBER;
|
||||
}
|
||||
|
||||
public boolean hasBoolean(String name) {
|
||||
return propMap.containsKey(name) && propMap.get(name).getValue().elementType() == JsonElementType.BOOLEAN;
|
||||
return propMap.containsKey(name) && propMap.get(name).getValue().type() == JsonElementType.BOOLEAN;
|
||||
}
|
||||
|
||||
public boolean hasNull(String name) {
|
||||
return propMap.containsKey(name) && propMap.get(name).getValue().elementType() == JsonElementType.NULL;
|
||||
return propMap.containsKey(name) && propMap.get(name).getValue().type() == JsonElementType.NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -349,5 +350,14 @@ public class JsonObject extends JsonElement {
|
|||
b.append(" }");
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
public boolean isExtraComma() {
|
||||
return extraComma;
|
||||
}
|
||||
|
||||
public void setExtraComma(boolean extraComma) {
|
||||
this.extraComma = extraComma;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ public class JsonString extends JsonPrimitive {
|
|||
private JsonString() {
|
||||
}
|
||||
|
||||
public JsonElementType elementType() {
|
||||
public JsonElementType type() {
|
||||
return JsonElementType.STRING;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.util.List;
|
|||
import java.util.Stack;
|
||||
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.json.model.JsonComment;
|
||||
import org.hl7.fhir.utilities.json.model.JsonElement;
|
||||
import org.hl7.fhir.utilities.json.model.JsonLocationData;
|
||||
|
||||
|
@ -46,7 +47,7 @@ public class JsonLexer {
|
|||
private StringBuilder b = new StringBuilder();
|
||||
private boolean allowComments;
|
||||
private boolean allowUnquotedStrings;
|
||||
private List<String> comments = new ArrayList<>();
|
||||
private List<JsonComment> comments = new ArrayList<>();
|
||||
private boolean isUnquoted;
|
||||
|
||||
public JsonLexer(String source, boolean allowComments, boolean allowUnquotedStrings) throws IOException {
|
||||
|
@ -166,6 +167,7 @@ public class JsonLexer {
|
|||
do {
|
||||
ch = getNextChar();
|
||||
if (allowComments && ch == '/') {
|
||||
JsonLocationData start = location.prev();
|
||||
char ch1 = getNextChar();
|
||||
if (ch1 == '/') {
|
||||
StringBuilder b = new StringBuilder();
|
||||
|
@ -174,7 +176,7 @@ public class JsonLexer {
|
|||
if (first) first = false; else b.append(ch);
|
||||
ch = getNextChar();
|
||||
}
|
||||
comments.add(b.toString().trim());
|
||||
comments.add(new JsonComment(b.toString().trim(), start, location.prev()));
|
||||
} else {
|
||||
push(ch1);
|
||||
}
|
||||
|
@ -293,5 +295,10 @@ public class JsonLexer {
|
|||
return isUnquoted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JsonLexer [cursor=" + cursor + ", peek=" + peek + ", type=" + type + ", location=" + location.toString() + "]";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.hl7.fhir.utilities.Utilities;
|
|||
import org.hl7.fhir.utilities.json.JsonException;
|
||||
import org.hl7.fhir.utilities.json.model.JsonArray;
|
||||
import org.hl7.fhir.utilities.json.model.JsonBoolean;
|
||||
import org.hl7.fhir.utilities.json.model.JsonComment;
|
||||
import org.hl7.fhir.utilities.json.model.JsonElement;
|
||||
import org.hl7.fhir.utilities.json.model.JsonElementType;
|
||||
import org.hl7.fhir.utilities.json.model.JsonLocationData;
|
||||
|
@ -305,6 +306,7 @@ public class JsonParser {
|
|||
|
||||
private void readObject(String path, JsonObject obj, boolean root) throws IOException, JsonException {
|
||||
while (!(itemType == ItemType.End) || (root && (itemType == ItemType.Eof))) {
|
||||
obj.setExtraComma(false);
|
||||
switch (itemType) {
|
||||
case Object:
|
||||
JsonObject child = new JsonObject(); //(obj.path+'.'+ItemName);
|
||||
|
@ -374,6 +376,7 @@ public class JsonParser {
|
|||
}
|
||||
itemNoComma = false;
|
||||
endProperty = lexer.getLocation().copy();
|
||||
obj.setExtraComma(lexer.getType() == TokenType.Comma);
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
@ -382,6 +385,7 @@ public class JsonParser {
|
|||
boolean res = false;
|
||||
while (!((itemType == ItemType.End) || (root && (itemType == ItemType.Eof)))) {
|
||||
res = true;
|
||||
arr.setExtraComma(false);
|
||||
switch (itemType) {
|
||||
case Object:
|
||||
JsonObject obj = new JsonObject(); // (arr.path+'['+inttostr(i)+']');
|
||||
|
@ -436,6 +440,7 @@ public class JsonParser {
|
|||
}
|
||||
itemNoComma = false;
|
||||
arr.setEnd(lexer.getLocation().copy());
|
||||
arr.setExtraComma(lexer.getType() == TokenType.Comma);
|
||||
next();
|
||||
}
|
||||
return res;
|
||||
|
@ -465,7 +470,12 @@ public class JsonParser {
|
|||
lexer.getStates().pop();
|
||||
if (lexer.getType() == TokenType.Comma) {
|
||||
lexer.next();
|
||||
parseProperty();
|
||||
if (allowNoComma && (lexer.getType() == TokenType.CloseArray || lexer.getType() == TokenType.Close)) {
|
||||
itemType = ItemType.End;
|
||||
lexer.next();
|
||||
} else {
|
||||
parseProperty();
|
||||
}
|
||||
} else if (lexer.getType() == TokenType.Close) {
|
||||
itemType = ItemType.End;
|
||||
lexer.next();
|
||||
|
@ -551,17 +561,17 @@ public class JsonParser {
|
|||
return b.toString();
|
||||
}
|
||||
|
||||
private void writeComments(StringBuilder b, List<String> comments, int indent) {
|
||||
for (String s : comments) {
|
||||
private void writeComments(StringBuilder b, List<JsonComment> comments, int indent) {
|
||||
for (JsonComment s : comments) {
|
||||
b.append("// ");
|
||||
b.append(s);
|
||||
b.append(s.getContent());
|
||||
b.append("\n");
|
||||
b.append(Utilities.padLeft("", ' ', indent));
|
||||
}
|
||||
}
|
||||
|
||||
private void write(StringBuilder b, JsonElement e, boolean pretty, int indent) {
|
||||
switch (e.elementType()) {
|
||||
switch (e.type()) {
|
||||
case ARRAY:
|
||||
JsonArray arr = (JsonArray) e;
|
||||
b.append("[");
|
||||
|
@ -573,7 +583,7 @@ public class JsonParser {
|
|||
if (i instanceof JsonPrimitive) {
|
||||
length = length + ((JsonPrimitive)i).toJson().length();
|
||||
}
|
||||
if (i.elementType() == JsonElementType.ARRAY || i.elementType() == JsonElementType.OBJECT
|
||||
if (i.type() == JsonElementType.ARRAY || i.type() == JsonElementType.OBJECT
|
||||
|| i.hasComments()) { // 20 is a somewhat arbitrary cut off
|
||||
complex = true;
|
||||
}
|
||||
|
|
|
@ -393,7 +393,7 @@ Error_parsing_JSON_the_primitive_value_must_be_a_number = Error parsing JSON: th
|
|||
Error_parsing_JSON_the_primitive_value_must_be_a_boolean = Error parsing JSON: the primitive value must be a boolean
|
||||
Error_parsing_XHTML_ = Error parsing XHTML: {0}
|
||||
This_property_must_be_an_object_not_ = This property must be an object, not {0} ({1} at {2})
|
||||
This_property_must_be_an_simple_value_not_ = This property must be an simple value, not {0} ({1} at {2})
|
||||
This_property_must_be_an_simple_value_not_ = This property must be a simple value, not {0} ({1} at {2})
|
||||
This_property_must_be__not_ = The property {2} must be {0}, not {1} (at {3})
|
||||
This_property_must_be_an_Array_not_ = The property {1} must be a JSON Array, not {0} (at {2})
|
||||
OBJECT_CANNOT_BE_KEYED_ARRAY_CHILD_COUNT = This object cannot be an keyed Array in Json because it does not have two children in the definitions (children = {0})
|
||||
|
@ -480,7 +480,7 @@ XHTML_URL_INVALID = The URL is not valid because ''({1})'': {0}
|
|||
MEASURE_MR_GRP_NO_CODE = Group should have a code that matches the group definition in the measure
|
||||
MEASURE_MR_GRP_UNK_CODE = The code for this group has no match in the measure definition
|
||||
MEASURE_MR_GRP_DUPL_CODE = The code for this group is duplicated with another group
|
||||
MEASURE_MR_GRP_MISSING_BY_CODE = The MeasureReport does not include a group for the group {0}
|
||||
MEASURE_MR_GRP_MISSING_BY_CODE = The MeasureReport does not include a group for the group ''{0}''
|
||||
MEASURE_MR_GRP_NO_USABLE_CODE = None of the codes provided are usable for comparison - need both system and code on at least one code
|
||||
MEASURE_MR_GRP_NO_WRONG_CODE = The code provided ({0}) does not match the code specified in the measure report ({1})
|
||||
DUPLICATE_ID = Duplicate id value ''{0}''
|
||||
|
@ -799,3 +799,11 @@ SD_CONSTRAINED_KIND_NO_MATCH = The kind {0} must be the same as the kind {1} in
|
|||
SD_PATH_TYPE_MISMATCH = The path {1} must start with the type of the structure {0}
|
||||
UNABLE_TO_RESOLVE_CONTENT_REFERENCE = Unable to resolve the content reference {0} on element {1} (path = {2})
|
||||
UNABLE_TO_RESOLVE_CONTENT_REFERENCE_IN_THIS_CONTEXT = Unable to resolve the content reference {0} on element {1} (path = {2}) in this context
|
||||
RESOURCETYPE_PROPERTY_WRONG_TYPE = The JSON element ''resourceType'' has the wrong JSON type: {0}
|
||||
DUPLICATE_JSON_PROPERTY = The JSON property ''{0}'' is a duplicate and will be ignored
|
||||
DUPLICATE_JSON_PROPERTY_KEY = The JSON property ''{0}'' is a duplicate and will be ignored
|
||||
JSON_PROPERTY_NO_QUOTES = The JSON property ''{0}'' has no quotes around the name of the property
|
||||
JSON_PROPERTY_VALUE_NO_QUOTES = The JSON property ''{0}'' has no quotes around the value of the property ''{1}''
|
||||
JSON_COMMA_MISSING = A Comma is missing in the JSON
|
||||
JSON_COMMA_EXTRA = There is an extra comma at the end of the {0} in the JSON
|
||||
JSON_COMMENTS_NOT_ALLOWED = Comments are not allowed in JSON
|
||||
|
|
|
@ -28,7 +28,12 @@ public class JsonParserTests {
|
|||
Assertions.assertEquals(0, obj.getComments().size());
|
||||
JsonString c = obj.getJsonString("n1");
|
||||
Assertions.assertEquals(1, c.getComments().size());
|
||||
Assertions.assertEquals("some comment", c.getComments().get(0));
|
||||
Assertions.assertEquals("some comment", c.getComments().get(0).getContent());
|
||||
Assertions.assertEquals(2, c.getComments().get(0).getStart().getLine());
|
||||
Assertions.assertEquals(3, c.getComments().get(0).getStart().getCol());
|
||||
Assertions.assertEquals(2, c.getComments().get(0).getEnd().getLine());
|
||||
Assertions.assertEquals(19, c.getComments().get(0).getEnd().getCol());
|
||||
Assertions.assertEquals("some comment", c.getComments().get(0).getContent());
|
||||
Assertions.assertEquals("{\"n1\":\"v1\"}", JsonParser.compose(obj, false));
|
||||
Assertions.assertEquals("{\n // some comment\n \"n1\" : \"v1\"\n}\n", JsonParser.compose(obj, true));
|
||||
}
|
||||
|
@ -37,7 +42,11 @@ public class JsonParserTests {
|
|||
public void testComments3() throws IOException, JsonException {
|
||||
JsonObject obj = JsonParser.parseObject("// some comment\n{\n \"n1\" : \"v1\"\n}\n", true);
|
||||
Assertions.assertEquals(1, obj.getComments().size());
|
||||
Assertions.assertEquals("some comment", obj.getComments().get(0));
|
||||
Assertions.assertEquals("some comment", obj.getComments().get(0).getContent());
|
||||
Assertions.assertEquals(1, obj.getComments().get(0).getStart().getLine());
|
||||
Assertions.assertEquals(1, obj.getComments().get(0).getStart().getCol());
|
||||
Assertions.assertEquals(1, obj.getComments().get(0).getEnd().getLine());
|
||||
Assertions.assertEquals(16, obj.getComments().get(0).getEnd().getCol());
|
||||
JsonString c = obj.getJsonString("n1");
|
||||
Assertions.assertEquals(0, c.getComments().size());
|
||||
Assertions.assertEquals("{\"n1\":\"v1\"}", JsonParser.compose(obj, false));
|
||||
|
@ -477,10 +486,10 @@ public class JsonParserTests {
|
|||
@Test
|
||||
public void testElementBool() throws IOException, JsonException {
|
||||
JsonElement e = JsonParser.parse("true");
|
||||
Assertions.assertEquals(JsonElementType.BOOLEAN, e.elementType());
|
||||
Assertions.assertEquals(JsonElementType.BOOLEAN, e.type());
|
||||
Assertions.assertEquals(true, ((JsonBoolean) e).isValue());
|
||||
e = JsonParser.parse("// comment\nfalse", true);
|
||||
Assertions.assertEquals(JsonElementType.BOOLEAN, e.elementType());
|
||||
Assertions.assertEquals(JsonElementType.BOOLEAN, e.type());
|
||||
Assertions.assertEquals(false, ((JsonBoolean) e).isValue());
|
||||
Assertions.assertEquals("false", JsonParser.compose(e));
|
||||
Assertions.assertEquals("// comment\nfalse\n", JsonParser.compose(e, true));
|
||||
|
@ -489,10 +498,10 @@ public class JsonParserTests {
|
|||
@Test
|
||||
public void testElementNumber() throws IOException, JsonException {
|
||||
JsonElement e = JsonParser.parse("1");
|
||||
Assertions.assertEquals(JsonElementType.NUMBER, e.elementType());
|
||||
Assertions.assertEquals(JsonElementType.NUMBER, e.type());
|
||||
Assertions.assertEquals("1", ((JsonNumber) e).getValue());
|
||||
e = JsonParser.parse("// comment \n-1.2e10", true);
|
||||
Assertions.assertEquals(JsonElementType.NUMBER, e.elementType());
|
||||
Assertions.assertEquals(JsonElementType.NUMBER, e.type());
|
||||
Assertions.assertEquals("-1.2e10", ((JsonNumber) e).getValue());
|
||||
Assertions.assertEquals("-1.2e10", JsonParser.compose(e));
|
||||
Assertions.assertEquals("// comment\n-1.2e10\n", JsonParser.compose(e, true));
|
||||
|
@ -501,19 +510,19 @@ public class JsonParserTests {
|
|||
@Test
|
||||
public void testElementString() throws IOException, JsonException {
|
||||
JsonElement e = JsonParser.parse("\"str\\ning\"");
|
||||
Assertions.assertEquals(JsonElementType.STRING, e.elementType());
|
||||
Assertions.assertEquals(JsonElementType.STRING, e.type());
|
||||
Assertions.assertEquals("str\ning", ((JsonString) e).getValue());
|
||||
Assertions.assertEquals("\"str\\ning\"", JsonParser.compose(e));
|
||||
Assertions.assertEquals("\"str\\ning\"\n", JsonParser.compose(e, true));
|
||||
e = JsonParser.parse("// comment\n\"\"", true);
|
||||
Assertions.assertEquals(JsonElementType.STRING, e.elementType());
|
||||
Assertions.assertEquals(JsonElementType.STRING, e.type());
|
||||
Assertions.assertEquals("", ((JsonString) e).getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testElementNull() throws IOException, JsonException {
|
||||
JsonElement e = JsonParser.parse("null");
|
||||
Assertions.assertEquals(JsonElementType.NULL, e.elementType());
|
||||
Assertions.assertEquals(JsonElementType.NULL, e.type());
|
||||
Assertions.assertEquals("null", JsonParser.compose(e));
|
||||
Assertions.assertEquals("null\n", JsonParser.compose(e, true));
|
||||
}
|
||||
|
@ -521,12 +530,12 @@ public class JsonParserTests {
|
|||
@Test
|
||||
public void testElementArray() throws IOException, JsonException {
|
||||
JsonElement e = JsonParser.parse("[\"test\", null, true]");
|
||||
Assertions.assertEquals(JsonElementType.ARRAY, e.elementType());
|
||||
Assertions.assertEquals(JsonElementType.ARRAY, e.type());
|
||||
Assertions.assertEquals(3, ((JsonArray) e).size());
|
||||
Assertions.assertEquals("[\"test\",null,true]", JsonParser.compose(e));
|
||||
Assertions.assertEquals("[\"test\", null, true]\n", JsonParser.compose(e, true));
|
||||
e = JsonParser.parse("// comment\n[]", true);
|
||||
Assertions.assertEquals(JsonElementType.ARRAY, e.elementType());
|
||||
Assertions.assertEquals(JsonElementType.ARRAY, e.type());
|
||||
Assertions.assertEquals(0, ((JsonArray) e).size());
|
||||
}
|
||||
|
||||
|
@ -567,8 +576,20 @@ public class JsonParserTests {
|
|||
Assertions.assertEquals(2, e.size());
|
||||
Assertions.assertEquals(false, e.isNoComma(0));
|
||||
Assertions.assertEquals(true, e.isNoComma(1));
|
||||
Assertions.assertEquals(false, e.isExtraComma());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNoCommainArr3() throws IOException, JsonException {
|
||||
JsonArray e = (JsonArray) JsonParser.parse("[1, 2 3,]", true);
|
||||
Assertions.assertEquals(3, e.size());
|
||||
Assertions.assertEquals(false, e.isNoComma(0));
|
||||
Assertions.assertEquals(false, e.isNoComma(1));
|
||||
Assertions.assertEquals(true, e.isNoComma(2));
|
||||
Assertions.assertEquals(true, e.isExtraComma());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testUnquoted1() throws IOException, JsonException {
|
||||
|
@ -583,5 +604,14 @@ public class JsonParserTests {
|
|||
Assertions.assertEquals(true, e.getProperties().get(0).isUnquotedValue());
|
||||
Assertions.assertEquals(false, e.getProperties().get(1).isUnquotedName());
|
||||
Assertions.assertEquals(true, e.getProperties().get(1).isUnquotedValue());
|
||||
Assertions.assertEquals(false, e.isExtraComma());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtraComma() throws IOException, JsonException {
|
||||
JsonObject o = (JsonObject) JsonParser.parse("{ \"a\" : \"b\", \"c\" : \"d\",}", true);
|
||||
Assertions.assertEquals(2, o.getProperties().size());
|
||||
Assertions.assertEquals(true, o.isExtraComma());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -172,6 +172,7 @@ import org.hl7.fhir.utilities.Utilities.DecimalStatus;
|
|||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities.VersionURLInfo;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
import org.hl7.fhir.utilities.json.model.JsonObject;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||
|
@ -199,9 +200,6 @@ import org.hl7.fhir.validation.instance.utils.ResourceValidationTracker;
|
|||
import org.hl7.fhir.validation.instance.utils.ValidatorHostContext;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
|
||||
/**
|
||||
* Thinking of using this in a java program? Don't!
|
||||
* You should use one of the wrappers instead. Either in HAPI, or use ValidationEngine
|
||||
|
@ -429,6 +427,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
private boolean wantCheckSnapshotUnchanged;
|
||||
private boolean noUnicodeBiDiControlChars;
|
||||
private HtmlInMarkdownCheck htmlInMarkdownCheck;
|
||||
private boolean allowComments;
|
||||
|
||||
private List<ImplementationGuide> igs = new ArrayList<>();
|
||||
private List<String> extensionDomains = new ArrayList<String>();
|
||||
|
@ -580,6 +579,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
this.allowExamples = value;
|
||||
}
|
||||
|
||||
public boolean isAllowComments() {
|
||||
return allowComments;
|
||||
}
|
||||
|
||||
public void setAllowComments(boolean allowComments) {
|
||||
this.allowComments = allowComments;
|
||||
}
|
||||
|
||||
public boolean isCrumbTrails() {
|
||||
return crumbTrails;
|
||||
}
|
||||
|
@ -677,6 +684,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
((XmlParser) parser).setAllowXsiLocation(allowXsiLocation);
|
||||
}
|
||||
parser.setupValidation(ValidationPolicy.EVERYTHING, errors);
|
||||
if (parser instanceof XmlParser) {
|
||||
((XmlParser) parser).setAllowXsiLocation(allowXsiLocation);
|
||||
}
|
||||
if (parser instanceof JsonParser) {
|
||||
((JsonParser) parser).setAllowComments(allowComments);
|
||||
}
|
||||
long t = System.nanoTime();
|
||||
List<NamedElement> list = null;
|
||||
try {
|
||||
|
|
|
@ -265,6 +265,9 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
|||
if (content.has("best-practice")) {
|
||||
val.setBestPracticeWarningLevel(BestPracticeWarningLevel.valueOf(content.get("best-practice").getAsString()));
|
||||
}
|
||||
if (content.has("allow-comments")) {
|
||||
val.setAllowComments(content.get("allow-comments").getAsBoolean());
|
||||
}
|
||||
if (content.has("examples")) {
|
||||
val.setAllowExamples(content.get("examples").getAsBoolean());
|
||||
} else {
|
||||
|
@ -368,9 +371,6 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
|||
checkOutcomes(errorsLogical, logical, "logical", name);
|
||||
}
|
||||
logger.verifyHasNoRequests();
|
||||
if (BUILD_NEW) {
|
||||
JsonTrackingParser.write(manifest, new File(Utilities.path("[tmp]", "validator", "manifest.new.json")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -444,6 +444,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
|||
OperationOutcome actual = OperationOutcomeUtilities.createOutcomeSimple(errors);
|
||||
actual.setText(null);
|
||||
String json = new JsonParser().setOutputStyle(OutputStyle.PRETTY).composeString(actual);
|
||||
|
||||
|
||||
List<String> fails = new ArrayList<>();
|
||||
|
||||
|
@ -482,7 +483,32 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
|||
logOutput(json);
|
||||
logOutput("");
|
||||
logOutput("========================================================");
|
||||
logOutput("");
|
||||
logOutput("");
|
||||
if (BUILD_NEW && actual.getIssue().size() > 0) {
|
||||
if (java.has("output")) {
|
||||
java.remove("output");
|
||||
}
|
||||
if (java.has("error-locations")) {
|
||||
java.remove("error-locations");
|
||||
}
|
||||
if (java.has("warningCount")) {
|
||||
java.remove("warningCount");
|
||||
}
|
||||
if (java.has("infoCount")) {
|
||||
java.remove("infoCount");
|
||||
}
|
||||
if (java.has("errorCount")) {
|
||||
java.remove("errorCount");
|
||||
}
|
||||
if (java.has("outcome")) {
|
||||
java.remove("outcome");
|
||||
}
|
||||
if (actual.hasIssue()) {
|
||||
JsonObject oj = JsonTrackingParser.parse(json, null);
|
||||
java.add("outcome", oj);
|
||||
}
|
||||
JsonTrackingParser.write(manifest, new File(Utilities.path("[tmp]", "validator", "manifest.new.json")));
|
||||
}
|
||||
Assertions.fail("\r\n"+String.join("\r\n", fails));
|
||||
}
|
||||
// int ec = 0;
|
||||
|
@ -526,30 +552,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
|
|||
// Assert.assertEquals("Location should be " + el.get(i).getAsString() + ", but was " + errLocs.get(i), errLocs.get(i), el.get(i).getAsString());
|
||||
// }
|
||||
// }
|
||||
if (BUILD_NEW) {
|
||||
if (java.has("output")) {
|
||||
java.remove("output");
|
||||
}
|
||||
if (java.has("error-locations")) {
|
||||
java.remove("error-locations");
|
||||
}
|
||||
if (java.has("warningCount")) {
|
||||
java.remove("warningCount");
|
||||
}
|
||||
if (java.has("infoCount")) {
|
||||
java.remove("infoCount");
|
||||
}
|
||||
if (java.has("errorCount")) {
|
||||
java.remove("errorCount");
|
||||
}
|
||||
if (java.has("outcome")) {
|
||||
java.remove("outcome");
|
||||
}
|
||||
if (actual.hasIssue()) {
|
||||
JsonObject oj = JsonTrackingParser.parse(json, null);
|
||||
java.add("outcome", oj);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void logOutput(String msg) {
|
||||
|
|
Loading…
Reference in New Issue