NPMPackage direct loading, + refactor JSON parser Location
This commit is contained in:
parent
079f3cb8b8
commit
d3ef2d7624
|
@ -41,13 +41,13 @@ import org.hl7.fhir.dstu3.formats.JsonCreatorCanonical;
|
|||
import org.hl7.fhir.dstu3.formats.JsonCreatorGson;
|
||||
import org.hl7.fhir.dstu3.model.ElementDefinition.TypeRefComponent;
|
||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu3.utils.formats.JsonTrackingParser;
|
||||
import org.hl7.fhir.dstu3.utils.formats.JsonTrackingParser.LocationData;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser.LocationData;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
|
||||
|
|
|
@ -1,519 +0,0 @@
|
|||
package org.hl7.fhir.dstu3.utils.formats;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* org.hl7.fhir.dstu3
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 Health Level 7
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* This is created to get a json parser that can track line numbers... grr...
|
||||
*
|
||||
* @author Grahame Grieve
|
||||
*
|
||||
*/
|
||||
public class JsonTrackingParser {
|
||||
|
||||
public enum TokenType {
|
||||
Open, Close, String, Number, Colon, Comma, OpenArray, CloseArray, Eof, Null, Boolean;
|
||||
}
|
||||
|
||||
public class LocationData {
|
||||
private int line;
|
||||
private int col;
|
||||
|
||||
protected LocationData(int line, int col) {
|
||||
super();
|
||||
this.line = line;
|
||||
this.col = col;
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
public int getCol() {
|
||||
return col;
|
||||
}
|
||||
|
||||
public void newLine() {
|
||||
line++;
|
||||
col = 1;
|
||||
}
|
||||
|
||||
public LocationData copy() {
|
||||
return new LocationData(line, col);
|
||||
}
|
||||
}
|
||||
|
||||
private class State {
|
||||
private String name;
|
||||
private boolean isProp;
|
||||
protected State(String name, boolean isProp) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.isProp = isProp;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public boolean isProp() {
|
||||
return isProp;
|
||||
}
|
||||
}
|
||||
|
||||
private class Lexer {
|
||||
private String source;
|
||||
private int cursor;
|
||||
private String peek;
|
||||
private String value;
|
||||
private TokenType type;
|
||||
private Stack<State> states = new Stack<State>();
|
||||
private LocationData lastLocationBWS;
|
||||
private LocationData lastLocationAWS;
|
||||
private LocationData location;
|
||||
private StringBuilder b = new StringBuilder();
|
||||
|
||||
public Lexer(String source) throws FHIRException {
|
||||
this.source = source;
|
||||
cursor = -1;
|
||||
location = new LocationData(1, 1);
|
||||
start();
|
||||
}
|
||||
|
||||
private boolean more() {
|
||||
return peek != null || cursor < source.length();
|
||||
}
|
||||
|
||||
private String getNext(int length) throws FHIRException {
|
||||
String result = "";
|
||||
if (peek != null) {
|
||||
if (peek.length() > length) {
|
||||
result = peek.substring(0, length);
|
||||
peek = peek.substring(length);
|
||||
} else {
|
||||
result = peek;
|
||||
peek = null;
|
||||
}
|
||||
}
|
||||
if (result.length() < length) {
|
||||
int len = length - result.length();
|
||||
if (cursor > source.length() - len)
|
||||
throw error("Attempt to read past end of source");
|
||||
result = result + source.substring(cursor+1, cursor+len+1);
|
||||
cursor = cursor + len;
|
||||
}
|
||||
for (char ch : result.toCharArray())
|
||||
if (ch == '\n')
|
||||
location.newLine();
|
||||
else
|
||||
location.col++;
|
||||
return result;
|
||||
}
|
||||
|
||||
private char getNextChar() throws FHIRException {
|
||||
if (peek != null) {
|
||||
char ch = peek.charAt(0);
|
||||
peek = peek.length() == 1 ? null : peek.substring(1);
|
||||
return ch;
|
||||
} else {
|
||||
cursor++;
|
||||
if (cursor >= source.length())
|
||||
return (char) 0;
|
||||
char ch = source.charAt(cursor);
|
||||
if (ch == '\n') {
|
||||
location.newLine();
|
||||
} else {
|
||||
location.col++;
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
|
||||
private void push(char ch){
|
||||
peek = peek == null ? String.valueOf(ch) : String.valueOf(ch)+peek;
|
||||
}
|
||||
|
||||
private void parseWord(String word, char ch, TokenType type) throws FHIRException {
|
||||
this.type = type;
|
||||
value = ""+ch+getNext(word.length()-1);
|
||||
if (!value.equals(word))
|
||||
throw error("Syntax error in json reading special word "+word);
|
||||
}
|
||||
|
||||
private FHIRException error(String msg) {
|
||||
return new FHIRException("Error parsing JSON source: "+msg+" at Line "+Integer.toString(location.line)+" (path=["+path()+"])");
|
||||
}
|
||||
|
||||
private String path() {
|
||||
if (states.empty())
|
||||
return value;
|
||||
else {
|
||||
String result = "";
|
||||
for (State s : states)
|
||||
result = result + '/'+ s.getName();
|
||||
result = result + value;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public void start() throws FHIRException {
|
||||
// char ch = getNextChar();
|
||||
// if (ch = '\.uEF')
|
||||
// begin
|
||||
// // skip BOM
|
||||
// getNextChar();
|
||||
// getNextChar();
|
||||
// end
|
||||
// else
|
||||
// push(ch);
|
||||
next();
|
||||
}
|
||||
|
||||
public TokenType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
public LocationData getLastLocationBWS() {
|
||||
return lastLocationBWS;
|
||||
}
|
||||
|
||||
public LocationData getLastLocationAWS() {
|
||||
return lastLocationAWS;
|
||||
}
|
||||
|
||||
public void next() throws FHIRException {
|
||||
lastLocationBWS = location.copy();
|
||||
char ch;
|
||||
do {
|
||||
ch = getNextChar();
|
||||
} while (more() && Utilities.charInSet(ch, ' ', '\r', '\n', '\t'));
|
||||
lastLocationAWS = location.copy();
|
||||
|
||||
if (!more()) {
|
||||
type = TokenType.Eof;
|
||||
} else {
|
||||
switch (ch) {
|
||||
case '{' :
|
||||
type = TokenType.Open;
|
||||
break;
|
||||
case '}' :
|
||||
type = TokenType.Close;
|
||||
break;
|
||||
case '"' :
|
||||
type = TokenType.String;
|
||||
b.setLength(0);
|
||||
do {
|
||||
ch = getNextChar();
|
||||
if (ch == '\\') {
|
||||
ch = getNextChar();
|
||||
switch (ch) {
|
||||
case '"': b.append('"'); break;
|
||||
case '\\': b.append('\\'); break;
|
||||
case '/': b.append('/'); break;
|
||||
case 'n': b.append('\n'); break;
|
||||
case 'r': b.append('\r'); break;
|
||||
case 't': b.append('\t'); break;
|
||||
case 'u': b.append((char) Integer.parseInt(getNext(4), 16)); break;
|
||||
default :
|
||||
throw error("unknown escape sequence: \\"+ch);
|
||||
}
|
||||
ch = ' ';
|
||||
} else if (ch != '"')
|
||||
b.append(ch);
|
||||
} while (more() && (ch != '"'));
|
||||
if (!more())
|
||||
throw error("premature termination of json stream during a string");
|
||||
value = b.toString();
|
||||
break;
|
||||
case ':' :
|
||||
type = TokenType.Colon;
|
||||
break;
|
||||
case ',' :
|
||||
type = TokenType.Comma;
|
||||
break;
|
||||
case '[' :
|
||||
type = TokenType.OpenArray;
|
||||
break;
|
||||
case ']' :
|
||||
type = TokenType.CloseArray;
|
||||
break;
|
||||
case 't' :
|
||||
parseWord("true", ch, TokenType.Boolean);
|
||||
break;
|
||||
case 'f' :
|
||||
parseWord("false", ch, TokenType.Boolean);
|
||||
break;
|
||||
case 'n' :
|
||||
parseWord("null", ch, TokenType.Null);
|
||||
break;
|
||||
default:
|
||||
if ((ch >= '0' && ch <= '9') || ch == '-') {
|
||||
type = TokenType.Number;
|
||||
b.setLength(0);
|
||||
while (more() && ((ch >= '0' && ch <= '9') || ch == '-' || ch == '.')) {
|
||||
b.append(ch);
|
||||
ch = getNextChar();
|
||||
}
|
||||
value = b.toString();
|
||||
push(ch);
|
||||
} else
|
||||
throw error("Unexpected char '"+ch+"' in json stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String consume(TokenType type) throws FHIRException {
|
||||
if (this.type != type)
|
||||
throw error("JSON syntax error - found "+type.toString()+" expecting "+type.toString());
|
||||
String result = value;
|
||||
next();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum ItemType {
|
||||
Object, String, Number, Boolean, Array, End, Eof, Null;
|
||||
}
|
||||
private Map<JsonElement, LocationData> map;
|
||||
private Lexer lexer;
|
||||
private ItemType itemType = ItemType.Object;
|
||||
private String itemName;
|
||||
private String itemValue;
|
||||
|
||||
public static JsonObject parse(String source, Map<JsonElement, LocationData> map) throws FHIRException {
|
||||
JsonTrackingParser self = new JsonTrackingParser();
|
||||
self.map = map;
|
||||
return self.parse(source);
|
||||
}
|
||||
|
||||
private JsonObject parse(String source) throws FHIRException {
|
||||
lexer = new Lexer(source);
|
||||
JsonObject result = new JsonObject();
|
||||
LocationData loc = lexer.location.copy();
|
||||
if (lexer.getType() == TokenType.Open) {
|
||||
lexer.next();
|
||||
lexer.states.push(new State("", false));
|
||||
}
|
||||
else
|
||||
throw lexer.error("Unexpected content at start of JSON: "+lexer.getType().toString());
|
||||
|
||||
parseProperty();
|
||||
readObject(result, true);
|
||||
map.put(result, loc);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void readObject(JsonObject obj, boolean root) throws FHIRException {
|
||||
map.put(obj, lexer.location.copy());
|
||||
|
||||
while (!(itemType == ItemType.End) || (root && (itemType == ItemType.Eof))) {
|
||||
if (obj.has(itemName))
|
||||
throw lexer.error("Duplicated property name: "+itemName);
|
||||
|
||||
switch (itemType) {
|
||||
case Object:
|
||||
JsonObject child = new JsonObject(); //(obj.path+'.'+ItemName);
|
||||
LocationData loc = lexer.location.copy();
|
||||
obj.add(itemName, child);
|
||||
next();
|
||||
readObject(child, false);
|
||||
map.put(obj, loc);
|
||||
break;
|
||||
case Boolean :
|
||||
JsonPrimitive v = new JsonPrimitive(Boolean.valueOf(itemValue));
|
||||
obj.add(itemName, v);
|
||||
map.put(v, lexer.location.copy());
|
||||
break;
|
||||
case String:
|
||||
v = new JsonPrimitive(itemValue);
|
||||
obj.add(itemName, v);
|
||||
map.put(v, lexer.location.copy());
|
||||
break;
|
||||
case Number:
|
||||
v = new JsonPrimitive(new BigDecimal(itemValue));
|
||||
obj.add(itemName, v);
|
||||
map.put(v, lexer.location.copy());
|
||||
break;
|
||||
case Null:
|
||||
JsonNull n = new JsonNull();
|
||||
obj.add(itemName, n);
|
||||
map.put(n, lexer.location.copy());
|
||||
break;
|
||||
case Array:
|
||||
JsonArray arr = new JsonArray(); // (obj.path+'.'+ItemName);
|
||||
loc = lexer.location.copy();
|
||||
obj.add(itemName, arr);
|
||||
next();
|
||||
readArray(arr, false);
|
||||
map.put(arr, loc);
|
||||
break;
|
||||
case Eof :
|
||||
throw lexer.error("Unexpected End of File");
|
||||
}
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
private void readArray(JsonArray arr, boolean root) throws FHIRException {
|
||||
while (!((itemType == ItemType.End) || (root && (itemType == ItemType.Eof)))) {
|
||||
switch (itemType) {
|
||||
case Object:
|
||||
JsonObject obj = new JsonObject(); // (arr.path+'['+inttostr(i)+']');
|
||||
LocationData loc = lexer.location.copy();
|
||||
arr.add(obj);
|
||||
next();
|
||||
readObject(obj, false);
|
||||
map.put(obj, loc);
|
||||
break;
|
||||
case String:
|
||||
JsonPrimitive v = new JsonPrimitive(itemValue);
|
||||
arr.add(v);
|
||||
map.put(v, lexer.location.copy());
|
||||
break;
|
||||
case Number:
|
||||
v = new JsonPrimitive(new BigDecimal(itemValue));
|
||||
arr.add(v);
|
||||
map.put(v, lexer.location.copy());
|
||||
break;
|
||||
case Null :
|
||||
JsonNull n = new JsonNull();
|
||||
arr.add(n);
|
||||
map.put(n, lexer.location.copy());
|
||||
break;
|
||||
case Array:
|
||||
JsonArray child = new JsonArray(); // (arr.path+'['+inttostr(i)+']');
|
||||
loc = lexer.location.copy();
|
||||
arr.add(child);
|
||||
next();
|
||||
readArray(child, false);
|
||||
map.put(arr, loc);
|
||||
break;
|
||||
case Eof :
|
||||
throw lexer.error("Unexpected End of File");
|
||||
}
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
private void next() throws FHIRException {
|
||||
switch (itemType) {
|
||||
case Object :
|
||||
lexer.consume(TokenType.Open);
|
||||
lexer.states.push(new State(itemName, false));
|
||||
if (lexer.getType() == TokenType.Close) {
|
||||
itemType = ItemType.End;
|
||||
lexer.next();
|
||||
} else
|
||||
parseProperty();
|
||||
break;
|
||||
case Null:
|
||||
case String:
|
||||
case Number:
|
||||
case End:
|
||||
case Boolean :
|
||||
if (itemType == ItemType.End)
|
||||
lexer.states.pop();
|
||||
if (lexer.getType() == TokenType.Comma) {
|
||||
lexer.next();
|
||||
parseProperty();
|
||||
} else if (lexer.getType() == TokenType.Close) {
|
||||
itemType = ItemType.End;
|
||||
lexer.next();
|
||||
} else if (lexer.getType() == TokenType.CloseArray) {
|
||||
itemType = ItemType.End;
|
||||
lexer.next();
|
||||
} else if (lexer.getType() == TokenType.Eof) {
|
||||
itemType = ItemType.Eof;
|
||||
} else
|
||||
throw lexer.error("Unexpected JSON syntax");
|
||||
break;
|
||||
case Array :
|
||||
lexer.next();
|
||||
lexer.states.push(new State(itemName+"[]", true));
|
||||
parseProperty();
|
||||
break;
|
||||
case Eof :
|
||||
throw lexer.error("JSON Syntax Error - attempt to read past end of json stream");
|
||||
default:
|
||||
throw lexer.error("not done yet (a): "+itemType.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void parseProperty() throws FHIRException {
|
||||
if (!lexer.states.peek().isProp) {
|
||||
itemName = lexer.consume(TokenType.String);
|
||||
itemValue = null;
|
||||
lexer.consume(TokenType.Colon);
|
||||
}
|
||||
switch (lexer.getType()) {
|
||||
case Null :
|
||||
itemType = ItemType.Null;
|
||||
itemValue = lexer.value;
|
||||
lexer.next();
|
||||
break;
|
||||
case String :
|
||||
itemType = ItemType.String;
|
||||
itemValue = lexer.value;
|
||||
lexer.next();
|
||||
break;
|
||||
case Boolean :
|
||||
itemType = ItemType.Boolean;
|
||||
itemValue = lexer.value;
|
||||
lexer.next();
|
||||
break;
|
||||
case Number :
|
||||
itemType = ItemType.Number;
|
||||
itemValue = lexer.value;
|
||||
lexer.next();
|
||||
break;
|
||||
case Open :
|
||||
itemType = ItemType.Object;
|
||||
break;
|
||||
case OpenArray :
|
||||
itemType = ItemType.Array;
|
||||
break;
|
||||
case CloseArray :
|
||||
itemType = ItemType.End;
|
||||
break;
|
||||
// case Close, , case Colon, case Comma, case OpenArray, !
|
||||
default:
|
||||
throw lexer.error("not done yet (b): "+lexer.getType().toString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,10 +44,10 @@ import org.hl7.fhir.r4.formats.JsonCreatorCanonical;
|
|||
import org.hl7.fhir.r4.formats.JsonCreatorGson;
|
||||
import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.utils.formats.JsonTrackingParser;
|
||||
import org.hl7.fhir.r4.utils.formats.JsonTrackingParser.LocationData;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser.LocationData;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
|
||||
|
|
|
@ -55,8 +55,8 @@ import org.hl7.fhir.exceptions.FHIRFormatError;
|
|||
|
||||
// Generated on Thu, Dec 13, 2018 14:07+1100 for FHIR v4.0.0
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.utils.formats.JsonTrackingParser.PresentedBigDecimal;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser.PresentedBigDecimal;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
|
|
|
@ -64,9 +64,9 @@ import org.hl7.fhir.r4.model.IdType;
|
|||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.hl7.fhir.r4.model.Type;
|
||||
import org.hl7.fhir.r4.utils.formats.JsonTrackingParser;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
|
||||
|
|
|
@ -1,556 +0,0 @@
|
|||
package org.hl7.fhir.r4.utils.formats;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* org.hl7.fhir.r4
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 Health Level 7
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* This is created to get a json parser that can track line numbers... grr...
|
||||
*
|
||||
* @author Grahame Grieve
|
||||
*
|
||||
*/
|
||||
public class JsonTrackingParser {
|
||||
|
||||
public class PresentedBigDecimal extends BigDecimal {
|
||||
|
||||
public String presentation;
|
||||
|
||||
public PresentedBigDecimal(String value) {
|
||||
super(value);
|
||||
presentation = value;
|
||||
}
|
||||
|
||||
public String getPresentation() {
|
||||
return presentation;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public enum TokenType {
|
||||
Open, Close, String, Number, Colon, Comma, OpenArray, CloseArray, Eof, Null, Boolean;
|
||||
}
|
||||
|
||||
public class LocationData {
|
||||
private int line;
|
||||
private int col;
|
||||
|
||||
protected LocationData(int line, int col) {
|
||||
super();
|
||||
this.line = line;
|
||||
this.col = col;
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
public int getCol() {
|
||||
return col;
|
||||
}
|
||||
|
||||
public void newLine() {
|
||||
line++;
|
||||
col = 1;
|
||||
}
|
||||
|
||||
public LocationData copy() {
|
||||
return new LocationData(line, col);
|
||||
}
|
||||
}
|
||||
|
||||
private class State {
|
||||
private String name;
|
||||
private boolean isProp;
|
||||
protected State(String name, boolean isProp) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.isProp = isProp;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public boolean isProp() {
|
||||
return isProp;
|
||||
}
|
||||
}
|
||||
|
||||
private class Lexer {
|
||||
private String source;
|
||||
private int cursor;
|
||||
private String peek;
|
||||
private String value;
|
||||
private TokenType type;
|
||||
private Stack<State> states = new Stack<State>();
|
||||
private LocationData lastLocationBWS;
|
||||
private LocationData lastLocationAWS;
|
||||
private LocationData location;
|
||||
private StringBuilder b = new StringBuilder();
|
||||
|
||||
public Lexer(String source) throws IOException {
|
||||
this.source = source;
|
||||
cursor = -1;
|
||||
location = new LocationData(1, 1);
|
||||
start();
|
||||
}
|
||||
|
||||
private boolean more() {
|
||||
return peek != null || cursor < source.length();
|
||||
}
|
||||
|
||||
private String getNext(int length) throws IOException {
|
||||
String result = "";
|
||||
if (peek != null) {
|
||||
if (peek.length() > length) {
|
||||
result = peek.substring(0, length);
|
||||
peek = peek.substring(length);
|
||||
} else {
|
||||
result = peek;
|
||||
peek = null;
|
||||
}
|
||||
}
|
||||
if (result.length() < length) {
|
||||
int len = length - result.length();
|
||||
if (cursor > source.length() - len)
|
||||
throw error("Attempt to read past end of source");
|
||||
result = result + source.substring(cursor+1, cursor+len+1);
|
||||
cursor = cursor + len;
|
||||
}
|
||||
for (char ch : result.toCharArray())
|
||||
if (ch == '\n')
|
||||
location.newLine();
|
||||
else
|
||||
location.col++;
|
||||
return result;
|
||||
}
|
||||
|
||||
private char getNextChar() throws IOException {
|
||||
if (peek != null) {
|
||||
char ch = peek.charAt(0);
|
||||
peek = peek.length() == 1 ? null : peek.substring(1);
|
||||
return ch;
|
||||
} else {
|
||||
cursor++;
|
||||
if (cursor >= source.length())
|
||||
return (char) 0;
|
||||
char ch = source.charAt(cursor);
|
||||
if (ch == '\n') {
|
||||
location.newLine();
|
||||
} else {
|
||||
location.col++;
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
|
||||
private void push(char ch){
|
||||
peek = peek == null ? String.valueOf(ch) : String.valueOf(ch)+peek;
|
||||
}
|
||||
|
||||
private void parseWord(String word, char ch, TokenType type) throws IOException {
|
||||
this.type = type;
|
||||
value = ""+ch+getNext(word.length()-1);
|
||||
if (!value.equals(word))
|
||||
throw error("Syntax error in json reading special word "+word);
|
||||
}
|
||||
|
||||
private IOException error(String msg) {
|
||||
return new IOException("Error parsing JSON source: "+msg+" at Line "+Integer.toString(location.line)+" (path=["+path()+"])");
|
||||
}
|
||||
|
||||
private String path() {
|
||||
if (states.empty())
|
||||
return value;
|
||||
else {
|
||||
String result = "";
|
||||
for (State s : states)
|
||||
result = result + '/'+ s.getName();
|
||||
result = result + value;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public void start() throws IOException {
|
||||
// char ch = getNextChar();
|
||||
// if (ch = '\.uEF')
|
||||
// begin
|
||||
// // skip BOM
|
||||
// getNextChar();
|
||||
// getNextChar();
|
||||
// end
|
||||
// else
|
||||
// push(ch);
|
||||
next();
|
||||
}
|
||||
|
||||
public TokenType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
public LocationData getLastLocationBWS() {
|
||||
return lastLocationBWS;
|
||||
}
|
||||
|
||||
public LocationData getLastLocationAWS() {
|
||||
return lastLocationAWS;
|
||||
}
|
||||
|
||||
public void next() throws IOException {
|
||||
lastLocationBWS = location.copy();
|
||||
char ch;
|
||||
do {
|
||||
ch = getNextChar();
|
||||
} while (more() && Utilities.charInSet(ch, ' ', '\r', '\n', '\t'));
|
||||
lastLocationAWS = location.copy();
|
||||
|
||||
if (!more()) {
|
||||
type = TokenType.Eof;
|
||||
} else {
|
||||
switch (ch) {
|
||||
case '{' :
|
||||
type = TokenType.Open;
|
||||
break;
|
||||
case '}' :
|
||||
type = TokenType.Close;
|
||||
break;
|
||||
case '"' :
|
||||
type = TokenType.String;
|
||||
b.setLength(0);
|
||||
do {
|
||||
ch = getNextChar();
|
||||
if (ch == '\\') {
|
||||
ch = getNextChar();
|
||||
switch (ch) {
|
||||
case '"': b.append('"'); break;
|
||||
case '\'': b.append('\''); break;
|
||||
case '\\': b.append('\\'); break;
|
||||
case '/': b.append('/'); break;
|
||||
case 'n': b.append('\n'); break;
|
||||
case 'r': b.append('\r'); break;
|
||||
case 't': b.append('\t'); break;
|
||||
case 'u': b.append((char) Integer.parseInt(getNext(4), 16)); break;
|
||||
default :
|
||||
throw error("unknown escape sequence: \\"+ch);
|
||||
}
|
||||
ch = ' ';
|
||||
} else if (ch != '"')
|
||||
b.append(ch);
|
||||
} while (more() && (ch != '"'));
|
||||
if (!more())
|
||||
throw error("premature termination of json stream during a string");
|
||||
value = b.toString();
|
||||
break;
|
||||
case ':' :
|
||||
type = TokenType.Colon;
|
||||
break;
|
||||
case ',' :
|
||||
type = TokenType.Comma;
|
||||
break;
|
||||
case '[' :
|
||||
type = TokenType.OpenArray;
|
||||
break;
|
||||
case ']' :
|
||||
type = TokenType.CloseArray;
|
||||
break;
|
||||
case 't' :
|
||||
parseWord("true", ch, TokenType.Boolean);
|
||||
break;
|
||||
case 'f' :
|
||||
parseWord("false", ch, TokenType.Boolean);
|
||||
break;
|
||||
case 'n' :
|
||||
parseWord("null", ch, TokenType.Null);
|
||||
break;
|
||||
default:
|
||||
if ((ch >= '0' && ch <= '9') || ch == '-') {
|
||||
type = TokenType.Number;
|
||||
b.setLength(0);
|
||||
while (more() && ((ch >= '0' && ch <= '9') || ch == '-' || ch == '.') || ch == '+' || ch == 'e' || ch == 'E') {
|
||||
b.append(ch);
|
||||
ch = getNextChar();
|
||||
}
|
||||
value = b.toString();
|
||||
push(ch);
|
||||
} else
|
||||
throw error("Unexpected char '"+ch+"' in json stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String consume(TokenType type) throws IOException {
|
||||
if (this.type != type)
|
||||
throw error("JSON syntax error - found "+type.toString()+" expecting "+type.toString());
|
||||
String result = value;
|
||||
next();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum ItemType {
|
||||
Object, String, Number, Boolean, Array, End, Eof, Null;
|
||||
}
|
||||
private Map<JsonElement, LocationData> map;
|
||||
private Lexer lexer;
|
||||
private ItemType itemType = ItemType.Object;
|
||||
private String itemName;
|
||||
private String itemValue;
|
||||
|
||||
public static JsonObject parse(String source, Map<JsonElement, LocationData> map) throws IOException {
|
||||
JsonTrackingParser self = new JsonTrackingParser();
|
||||
self.map = map;
|
||||
return self.parse(source);
|
||||
}
|
||||
|
||||
private JsonObject parse(String source) throws IOException {
|
||||
lexer = new Lexer(source);
|
||||
JsonObject result = new JsonObject();
|
||||
LocationData loc = lexer.location.copy();
|
||||
if (lexer.getType() == TokenType.Open) {
|
||||
lexer.next();
|
||||
lexer.states.push(new State("", false));
|
||||
}
|
||||
else
|
||||
throw lexer.error("Unexpected content at start of JSON: "+lexer.getType().toString());
|
||||
|
||||
parseProperty();
|
||||
readObject(result, true);
|
||||
if (map != null)
|
||||
map.put(result, loc);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void readObject(JsonObject obj, boolean root) throws IOException {
|
||||
if (map != null)
|
||||
map.put(obj, lexer.location.copy());
|
||||
|
||||
while (!(itemType == ItemType.End) || (root && (itemType == ItemType.Eof))) {
|
||||
if (obj.has(itemName))
|
||||
throw lexer.error("Duplicated property name: "+itemName);
|
||||
|
||||
switch (itemType) {
|
||||
case Object:
|
||||
JsonObject child = new JsonObject(); //(obj.path+'.'+ItemName);
|
||||
LocationData loc = lexer.location.copy();
|
||||
obj.add(itemName, child);
|
||||
next();
|
||||
readObject(child, false);
|
||||
if (map != null)
|
||||
map.put(obj, loc);
|
||||
break;
|
||||
case Boolean :
|
||||
JsonPrimitive v = new JsonPrimitive(Boolean.valueOf(itemValue));
|
||||
obj.add(itemName, v);
|
||||
if (map != null)
|
||||
map.put(v, lexer.location.copy());
|
||||
break;
|
||||
case String:
|
||||
v = new JsonPrimitive(itemValue);
|
||||
obj.add(itemName, v);
|
||||
if (map != null)
|
||||
map.put(v, lexer.location.copy());
|
||||
break;
|
||||
case Number:
|
||||
v = new JsonPrimitive(new PresentedBigDecimal(itemValue));
|
||||
obj.add(itemName, v);
|
||||
if (map != null)
|
||||
map.put(v, lexer.location.copy());
|
||||
break;
|
||||
case Null:
|
||||
JsonNull n = new JsonNull();
|
||||
obj.add(itemName, n);
|
||||
if (map != null)
|
||||
map.put(n, lexer.location.copy());
|
||||
break;
|
||||
case Array:
|
||||
JsonArray arr = new JsonArray(); // (obj.path+'.'+ItemName);
|
||||
loc = lexer.location.copy();
|
||||
obj.add(itemName, arr);
|
||||
next();
|
||||
readArray(arr, false);
|
||||
if (map != null)
|
||||
map.put(arr, loc);
|
||||
break;
|
||||
case Eof :
|
||||
throw lexer.error("Unexpected End of File");
|
||||
case End:
|
||||
// TODO GG: This isn't handled. Should it be?
|
||||
break;
|
||||
}
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
private void readArray(JsonArray arr, boolean root) throws IOException {
|
||||
while (!((itemType == ItemType.End) || (root && (itemType == ItemType.Eof)))) {
|
||||
switch (itemType) {
|
||||
case Object:
|
||||
JsonObject obj = new JsonObject(); // (arr.path+'['+inttostr(i)+']');
|
||||
LocationData loc = lexer.location.copy();
|
||||
arr.add(obj);
|
||||
next();
|
||||
readObject(obj, false);
|
||||
if (map != null)
|
||||
map.put(obj, loc);
|
||||
break;
|
||||
case String:
|
||||
JsonPrimitive v = new JsonPrimitive(itemValue);
|
||||
arr.add(v);
|
||||
if (map != null)
|
||||
map.put(v, lexer.location.copy());
|
||||
break;
|
||||
case Number:
|
||||
v = new JsonPrimitive(new BigDecimal(itemValue));
|
||||
arr.add(v);
|
||||
if (map != null)
|
||||
map.put(v, lexer.location.copy());
|
||||
break;
|
||||
case Null :
|
||||
JsonNull n = new JsonNull();
|
||||
arr.add(n);
|
||||
if (map != null)
|
||||
map.put(n, lexer.location.copy());
|
||||
break;
|
||||
case Array:
|
||||
JsonArray child = new JsonArray(); // (arr.path+'['+inttostr(i)+']');
|
||||
loc = lexer.location.copy();
|
||||
arr.add(child);
|
||||
next();
|
||||
readArray(child, false);
|
||||
if (map != null)
|
||||
map.put(arr, loc);
|
||||
break;
|
||||
case Eof :
|
||||
throw lexer.error("Unexpected End of File");
|
||||
case End:
|
||||
case Boolean:
|
||||
// TODO GG: These aren't handled. SHould they be?
|
||||
break;
|
||||
}
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
private void next() throws IOException {
|
||||
switch (itemType) {
|
||||
case Object :
|
||||
lexer.consume(TokenType.Open);
|
||||
lexer.states.push(new State(itemName, false));
|
||||
if (lexer.getType() == TokenType.Close) {
|
||||
itemType = ItemType.End;
|
||||
lexer.next();
|
||||
} else
|
||||
parseProperty();
|
||||
break;
|
||||
case Null:
|
||||
case String:
|
||||
case Number:
|
||||
case End:
|
||||
case Boolean :
|
||||
if (itemType == ItemType.End)
|
||||
lexer.states.pop();
|
||||
if (lexer.getType() == TokenType.Comma) {
|
||||
lexer.next();
|
||||
parseProperty();
|
||||
} else if (lexer.getType() == TokenType.Close) {
|
||||
itemType = ItemType.End;
|
||||
lexer.next();
|
||||
} else if (lexer.getType() == TokenType.CloseArray) {
|
||||
itemType = ItemType.End;
|
||||
lexer.next();
|
||||
} else if (lexer.getType() == TokenType.Eof) {
|
||||
itemType = ItemType.Eof;
|
||||
} else
|
||||
throw lexer.error("Unexpected JSON syntax");
|
||||
break;
|
||||
case Array :
|
||||
lexer.next();
|
||||
lexer.states.push(new State(itemName+"[]", true));
|
||||
parseProperty();
|
||||
break;
|
||||
case Eof :
|
||||
throw lexer.error("JSON Syntax Error - attempt to read past end of json stream");
|
||||
default:
|
||||
throw lexer.error("not done yet (a): "+itemType.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void parseProperty() throws IOException {
|
||||
if (!lexer.states.peek().isProp) {
|
||||
itemName = lexer.consume(TokenType.String);
|
||||
itemValue = null;
|
||||
lexer.consume(TokenType.Colon);
|
||||
}
|
||||
switch (lexer.getType()) {
|
||||
case Null :
|
||||
itemType = ItemType.Null;
|
||||
itemValue = lexer.value;
|
||||
lexer.next();
|
||||
break;
|
||||
case String :
|
||||
itemType = ItemType.String;
|
||||
itemValue = lexer.value;
|
||||
lexer.next();
|
||||
break;
|
||||
case Boolean :
|
||||
itemType = ItemType.Boolean;
|
||||
itemValue = lexer.value;
|
||||
lexer.next();
|
||||
break;
|
||||
case Number :
|
||||
itemType = ItemType.Number;
|
||||
itemValue = lexer.value;
|
||||
lexer.next();
|
||||
break;
|
||||
case Open :
|
||||
itemType = ItemType.Object;
|
||||
break;
|
||||
case OpenArray :
|
||||
itemType = ItemType.Array;
|
||||
break;
|
||||
case CloseArray :
|
||||
itemType = ItemType.End;
|
||||
break;
|
||||
// case Close, , case Colon, case Comma, case OpenArray, !
|
||||
default:
|
||||
throw lexer.error("not done yet (b): "+lexer.getType().toString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,10 +44,10 @@ import org.hl7.fhir.r5.formats.JsonCreatorCanonical;
|
|||
import org.hl7.fhir.r5.formats.JsonCreatorGson;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.utils.formats.JsonTrackingParser;
|
||||
import org.hl7.fhir.r5.utils.formats.JsonTrackingParser.LocationData;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser.LocationData;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
|
||||
|
|
|
@ -55,8 +55,8 @@ import org.hl7.fhir.exceptions.FHIRFormatError;
|
|||
|
||||
// Generated on Thu, Dec 13, 2018 14:07+1100 for FHIR v4.0.0
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.utils.formats.JsonTrackingParser.PresentedBigDecimal;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser.PresentedBigDecimal;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
|
|
|
@ -64,9 +64,9 @@ import org.hl7.fhir.r5.model.IdType;
|
|||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.r5.model.StringType;
|
||||
import org.hl7.fhir.r5.model.Type;
|
||||
import org.hl7.fhir.r5.utils.formats.JsonTrackingParser;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
|
||||
|
|
|
@ -37,11 +37,16 @@ import java.util.Map.Entry;
|
|||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
|
||||
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.hl7.fhir.utilities.IniFile;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.cache.PackageCacheManager.PackageEntry;
|
||||
import org.hl7.fhir.utilities.cache.PackageGenerator.PackageType;
|
||||
import org.hl7.fhir.utilities.json.JsonTrackingParser;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
|
@ -91,6 +96,39 @@ import com.google.gson.JsonObject;
|
|||
return names;
|
||||
}
|
||||
|
||||
private static final int BUFFER_SIZE = 1024;
|
||||
public static NpmPackage fromPackage(InputStream tgz) throws IOException {
|
||||
NpmPackage res = new NpmPackage(null);
|
||||
GzipCompressorInputStream gzipIn = new GzipCompressorInputStream(tgz);
|
||||
try (TarArchiveInputStream tarIn = new TarArchiveInputStream(gzipIn)) {
|
||||
TarArchiveEntry entry;
|
||||
|
||||
int i = 0;
|
||||
int c = 12;
|
||||
while ((entry = (TarArchiveEntry) tarIn.getNextEntry()) != null) {
|
||||
i++;
|
||||
if (entry.isDirectory()) {
|
||||
res.folders.add(entry.getName());
|
||||
} else {
|
||||
int count;
|
||||
byte data[] = new byte[BUFFER_SIZE];
|
||||
|
||||
ByteArrayOutputStream fos = new ByteArrayOutputStream();
|
||||
try (BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) {
|
||||
while ((count = tarIn.read(data, 0, BUFFER_SIZE)) != -1) {
|
||||
dest.write(data, 0, count);
|
||||
}
|
||||
}
|
||||
fos.close();
|
||||
res.content.put(entry.getName(), fos.toByteArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
res.npm = JsonTrackingParser.parseJson(res.content.get("package/package.json"));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
public static NpmPackage fromZip(InputStream stream, boolean dropRootFolder) throws IOException {
|
||||
NpmPackage res = new NpmPackage(null);
|
||||
ZipInputStream zip = new ZipInputStream(stream);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package org.hl7.fhir.r5.utils.formats;
|
||||
package org.hl7.fhir.utilities.json;
|
||||
|
||||
import java.io.File;
|
||||
|
Loading…
Reference in New Issue