Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
parseWithPath function equipped with path tracking.
  • Loading branch information
SiyaoIsHiding committed Jan 25, 2023
commit 30aacba6482278962354450a32c5096c3fbfcccb
10 changes: 3 additions & 7 deletions src/main/java/org/json/JSONPointer.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,9 @@ public static Builder builder() {
// Segments for the JSONPointer string
private final List<String> refTokens;
// Jane: add some fields and functions to access the next refTokens
private int currentInd;

public String nextKey(){
if (currentInd + 1 <= this.refTokens.size()){
return refTokens.get(currentInd++);
}
return "";
public List<String> getRefTokens(){
// read only
return new ArrayList<>(this.refTokens);
}

/**
Expand Down
254 changes: 252 additions & 2 deletions src/main/java/org/json/XML.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import java.io.StringReader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


/**
Expand Down Expand Up @@ -423,7 +425,7 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP
context.accumulate(tagName, jsonObject);
}
}

return false;
}
}
Expand All @@ -435,6 +437,238 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP
}
}

// Jane

public static boolean parseWithPath(XMLTokener x, JSONObject context, String name, XMLParserConfiguration config, List<String> currPath, List<String> targetPath, JSONObject to)
throws JSONException {
char c;
int i;
JSONObject jsonObject = null;
String string;
String tagName;
Object token;
XMLXsiTypeConverter<?> xmlXsiTypeConverter;

// Test for and skip past these forms:
// <!-- ... -->
// <! ... >
// <![ ... ]]>
// <? ... ?>
// Report errors for these forms:
// <>
// <=
// <<

token = x.nextToken();

// <!

if (token == BANG) {
c = x.next();
if (c == '-') {
if (x.next() == '-') {
x.skipPast("-->");
return false;
}
x.back();
} else if (c == '[') {
token = x.nextToken();
if ("CDATA".equals(token)) {
if (x.next() == '[') {
string = x.nextCDATA();
if (string.length() > 0) {
currPath.add(config.getcDataTagName());
context.accumulate(config.getcDataTagName(), string);
currPath.remove(currPath.size()-1);
}
return false;
}
}
throw x.syntaxError("Expected 'CDATA['");
}
i = 1;
do {
token = x.nextMeta();
if (token == null) {
throw x.syntaxError("Missing '>' after '<!'.");
} else if (token == LT) {
i += 1;
} else if (token == GT) {
i -= 1;
}
} while (i > 0);
return false;
} else if (token == QUEST) {

// <?
x.skipPast("?>");
return false;
} else if (token == SLASH) {

// Close tag </

token = x.nextToken();
if (name == null) {
throw x.syntaxError("Mismatched close tag " + token);
}
if (!token.equals(name)) {
throw x.syntaxError("Mismatched " + name + " and " + token);
}
if (x.nextToken() != GT) {
throw x.syntaxError("Misshaped close tag");
}
return true;

} else if (token instanceof Character) {
throw x.syntaxError("Misshaped tag");

// Open tag <

} else {
tagName = (String) token;

token = null;
jsonObject = new JSONObject();
boolean nilAttributeFound = false;
xmlXsiTypeConverter = null;
for (;;) {
if (token == null) {
token = x.nextToken();
}
// attribute = value
if (token instanceof String) {
string = (String) token;
token = x.nextToken();
currPath.add(tagName);
if (token == EQ) {
token = x.nextToken();
if (!(token instanceof String)) {
throw x.syntaxError("Missing value");
}

if (config.isConvertNilAttributeToNull()
&& NULL_ATTR.equals(string)
&& Boolean.parseBoolean((String) token)) {
nilAttributeFound = true;
} else if(config.getXsiTypeMap() != null && !config.getXsiTypeMap().isEmpty()
&& TYPE_ATTR.equals(string)) {
xmlXsiTypeConverter = config.getXsiTypeMap().get(token);
} else if (!nilAttributeFound) {
if (isTwoPathSame(currPath,targetPath)){
System.out.println("Target found");
}
currPath.add(string);
jsonObject.accumulate(string,
config.isKeepStrings()
? ((String) token)
: stringToValue((String) token));
currPath.remove(currPath.size()-1);
}
token = null;
} else {
currPath.add(string);
jsonObject.accumulate(string, "");
currPath.remove(currPath.size()-1);
}

currPath.remove(currPath.size()-1);

} else if (token == SLASH) {
// Empty tag <.../>
if (x.nextToken() != GT) {
throw x.syntaxError("Misshaped tag");
}
if (config.getForceList().contains(tagName)) {
// Force the value to be an array
if (nilAttributeFound) {
context.append(tagName, JSONObject.NULL);
} else if (jsonObject.length() > 0) {
context.append(tagName, jsonObject);
} else {
context.put(tagName, new JSONArray());
}
} else {
currPath.add(tagName);
if (nilAttributeFound) {
context.accumulate(tagName, JSONObject.NULL);
} else if (jsonObject.length() > 0) {
context.accumulate(tagName, jsonObject);
} else {
context.accumulate(tagName, "");
}
currPath.remove(currPath.size()-1);
}
return false;

} else if (token == GT) {
// Content, between <...> and </...>
for (;;) {
token = x.nextContent();
if (token == null) {
if (tagName != null) {
throw x.syntaxError("Unclosed tag " + tagName);
}
return false;
} else if (token instanceof String) {
string = (String) token;
if (string.length() > 0) {
currPath.add(config.getcDataTagName());
if(xmlXsiTypeConverter != null) {
jsonObject.accumulate(config.getcDataTagName(),
stringToValue(string, xmlXsiTypeConverter));
} else {
jsonObject.accumulate(config.getcDataTagName(),
config.isKeepStrings() ? string : stringToValue(string));
}
currPath.remove(currPath.size()-1);
}

} else if (token == LT) {
// Nested element
currPath.add(tagName);
if (parseWithPath(x, jsonObject, tagName, config, currPath, targetPath, to)) {
if (config.getForceList().contains(tagName)) {
// Force the value to be an array

if (jsonObject.length() == 0) {
context.put(tagName, new JSONArray());
} else if (jsonObject.length() == 1
&& jsonObject.opt(config.getcDataTagName()) != null) {
context.append(tagName, jsonObject.opt(config.getcDataTagName()));
} else {
context.append(tagName, jsonObject);
}
System.out.println(currPath.toString() + jsonObject.toString());
// currPath.remove(currPath.size()-1);
} else {
// currPath.add(tagName);
if (jsonObject.length() == 0) {
context.accumulate(tagName, "");
} else if (jsonObject.length() == 1
&& jsonObject.opt(config.getcDataTagName()) != null) {
context.accumulate(tagName, jsonObject.opt(config.getcDataTagName()));
} else {
context.accumulate(tagName, jsonObject);
}
System.out.println(currPath.toString() + jsonObject.toString());
// currPath.remove(currPath.size()-1);
}
currPath.remove(currPath.size()-1);
return false;
}else{
currPath.remove(currPath.size()-1);
}

}
}
} else {
throw x.syntaxError("Misshaped tag");
}
}
}
}


/**
* This method tries to convert the given string value to the target object
* @param string String to convert
Expand Down Expand Up @@ -567,7 +801,23 @@ public static JSONObject toJSONObject(Reader reader, JSONPointer path){

//TODO: For Jane
public static JSONObject toJSONObject(Reader reader, JSONPointer path, JSONObject replacement){
return new JSONObject();
JSONObject jo = new JSONObject();
XMLTokener x = new XMLTokener(reader);
while (x.more()) {
x.skipPast("<");
if(x.more()) {
parseWithPath(x, jo, null, XMLParserConfiguration.ORIGINAL, new ArrayList<String>(), path.getRefTokens(), replacement);
}
}
return jo;
}

private static boolean isTwoPathSame(List<String> aPath, List<String> anotherPath){
if (aPath.size()!=anotherPath.size()) return false;
for (int i = 0; i < aPath.size(); i++){
if (!aPath.get(i).equals(anotherPath.get(i))) return false;
}
return true;
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
Expand Down
18 changes: 9 additions & 9 deletions src/test/java/org/json/junit/JSONPointerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ private Object query(String pointer) {
}

// Jane: nextKey() unit tests
@Test
public void nextKeyTest(){
JSONPointer pointer = new JSONPointer("/obj/other~0key/another~1key/0");
assertEquals("obj", pointer.nextKey());
assertEquals("other~key", pointer.nextKey());
assertEquals("another/key", pointer.nextKey());
assertEquals("0", pointer.nextKey());
assertEquals("", pointer.nextKey());
}
// @Test
// public void nextKeyTest(){
// JSONPointer pointer = new JSONPointer("/obj/other~0key/another~1key/0");
// assertEquals("obj", pointer.nextKey());
// assertEquals("other~key", pointer.nextKey());
// assertEquals("another/key", pointer.nextKey());
// assertEquals("0", pointer.nextKey());
// assertEquals("", pointer.nextKey());
// }
@Test
public void emptyPointer() {
assertTrue(new JSONObject(EXPECTED_COMPLETE_DOCUMENT).similar(query("")));
Expand Down
39 changes: 39 additions & 0 deletions src/test/java/org/json/junit/XMLTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,45 @@ public void shouldHandleSimpleXML() {
compareFileToJSONObject(xmlStr, expectedStr);
}

// Jane test parseWithPath
@Test
public void testParseWithPath(){
String xmlStr =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+
"<addresses xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""+
" xsi:noNamespaceSchemaLocation='test.xsd'>\n"+
" <address>\n"+
" <name>Joe Tester</name>\n"+
" <street>[CDATA[Baker street 5]</street>\n"+
" <NothingHere/>\n"+
" <TrueValue>true</TrueValue>\n"+
" <FalseValue>false</FalseValue>\n"+
" <NullValue>null</NullValue>\n"+
" <PositiveValue>42</PositiveValue>\n"+
" <NegativeValue>-23</NegativeValue>\n"+
" <DoubleValue>-23.45</DoubleValue>\n"+
" <Nan>-23x.45</Nan>\n"+
" <ArrayOfNum>1, 2, 3, 4.1, 5.2</ArrayOfNum>\n"+
" </address>\n"+
"</addresses>";

String expectedStr =
"{\"addresses\":{\"address\":{\"street\":\"[CDATA[Baker street 5]\","+
"\"name\":\"Joe Tester\",\"NothingHere\":\"\",TrueValue:true,\n"+
"\"FalseValue\":false,\"NullValue\":null,\"PositiveValue\":42,\n"+
"\"NegativeValue\":-23,\"DoubleValue\":-23.45,\"Nan\":-23x.45,\n"+
"\"ArrayOfNum\":\"1, 2, 3, 4.1, 5.2\"\n"+
"},\"xsi:noNamespaceSchemaLocation\":"+
"\"test.xsd\",\"xmlns:xsi\":\"http://www.w3.org/2001/"+
"XMLSchema-instance\"}}";

JSONObject expectedJsonObject = new JSONObject(expectedStr);
Reader reader = new StringReader(xmlStr);
JSONPointer pointer = new JSONPointer("/addresses/address/TrueValue");
JSONObject jsonObject = XML.toJSONObject(reader, pointer, new JSONObject());
}


/**
* Tests to verify that supported escapes in XML are converted to actual values.
*/
Expand Down