Skip to content

Commit 4f14d9b

Browse files
committed
add custom prefix method, waiting for further improvement
1 parent f369612 commit 4f14d9b

File tree

2 files changed

+298
-0
lines changed

2 files changed

+298
-0
lines changed

src/main/java/org/json/XML.java

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,237 @@ private static boolean parse(XMLTokener x, JSONObject context, String name, XMLP
482482
}
483483
}
484484
}
485+
486+
// overwritten method of parse which allows to pass a prefix tag
487+
private static boolean parse(XMLTokener x, JSONObject context, String name, String prefix, XMLParserConfiguration config, int currentNestingDepth)
488+
throws JSONException {
489+
char c;
490+
int i;
491+
JSONObject jsonObject = null;
492+
String string;
493+
String tagName;
494+
Object token;
495+
XMLXsiTypeConverter<?> xmlXsiTypeConverter;
496+
497+
// Test for and skip past these forms:
498+
// <!-- ... -->
499+
// <! ... >
500+
// <![ ... ]]>
501+
// <? ... ?>
502+
// Report errors for these forms:
503+
// <>
504+
// <=
505+
// <<
506+
token = x.nextToken();
507+
508+
// <!
509+
if (token == BANG) {
510+
c = x.next();
511+
if (c == '-') {
512+
if (x.next() == '-') {
513+
x.skipPast("-->");
514+
return false;
515+
}
516+
x.back();
517+
} else if (c == '[') {
518+
token = x.nextToken();
519+
if ("CDATA".equals(token)) {
520+
if (x.next() == '[') {
521+
string = x.nextCDATA();
522+
if (string.length() > 0) {
523+
context.accumulate(config.getcDataTagName(), string);
524+
}
525+
return false;
526+
}
527+
}
528+
throw x.syntaxError("Expected 'CDATA['");
529+
}
530+
i = 1;
531+
do {
532+
token = x.nextMeta();
533+
if (token == null) {
534+
throw x.syntaxError("Missing '>' after '<!'.");
535+
} else if (token == LT) {
536+
i += 1;
537+
} else if (token == GT) {
538+
i -= 1;
539+
}
540+
} while (i > 0);
541+
return false;
542+
} else if (token == QUEST) {
543+
544+
// <?
545+
x.skipPast("?>");
546+
return false;
547+
} else if (token == SLASH) {
548+
549+
// Close tag </
550+
551+
token = x.nextToken();
552+
if (name == null) {
553+
throw x.syntaxError("Mismatched close tag " + token);
554+
}
555+
if (!token.equals(name)) {
556+
throw x.syntaxError("Mismatched " + name + " and " + token);
557+
}
558+
if (x.nextToken() != GT) {
559+
throw x.syntaxError("Misshaped close tag");
560+
}
561+
return true;
562+
563+
} else if (token instanceof Character) {
564+
throw x.syntaxError("Misshaped tag");
565+
566+
// Open tag <
567+
568+
} else {
569+
tagName = (String) token;
570+
token = null;
571+
jsonObject = new JSONObject();
572+
boolean nilAttributeFound = false;
573+
xmlXsiTypeConverter = null;
574+
for (;;) {
575+
if (token == null) {
576+
token = x.nextToken();
577+
}
578+
// attribute = value
579+
if (token instanceof String) {
580+
string = (String) token;
581+
token = x.nextToken();
582+
if (token == EQ) {
583+
token = x.nextToken();
584+
if (!(token instanceof String)) {
585+
throw x.syntaxError("Missing value");
586+
}
587+
588+
if (config.isConvertNilAttributeToNull()
589+
&& NULL_ATTR.equals(string)
590+
&& Boolean.parseBoolean((String) token)) {
591+
nilAttributeFound = true;
592+
} else if(config.getXsiTypeMap() != null && !config.getXsiTypeMap().isEmpty()
593+
&& TYPE_ATTR.equals(string)) {
594+
xmlXsiTypeConverter = config.getXsiTypeMap().get(token);
595+
} else if (!nilAttributeFound) {
596+
Object obj = stringToValue((String) token);
597+
if (obj instanceof Boolean) {
598+
jsonObject.accumulate(prefix + string,
599+
config.isKeepBooleanAsString()
600+
? ((String) token)
601+
: obj);
602+
} else if (obj instanceof Number) {
603+
jsonObject.accumulate(prefix + string,
604+
config.isKeepNumberAsString()
605+
? ((String) token)
606+
: obj);
607+
} else {
608+
jsonObject.accumulate(prefix + string, stringToValue((String) token));
609+
}
610+
}
611+
token = null;
612+
} else {
613+
jsonObject.accumulate(prefix + string, "");
614+
}
615+
616+
617+
} else if (token == SLASH) {
618+
// Empty tag <.../>
619+
if (x.nextToken() != GT) {
620+
throw x.syntaxError("Misshaped tag");
621+
}
622+
if (config.getForceList().contains(prefix + tagName)) {
623+
// Force the value to be an array
624+
if (nilAttributeFound) {
625+
context.append(prefix + tagName, JSONObject.NULL);
626+
} else if (jsonObject.length() > 0) {
627+
context.append(prefix + tagName, jsonObject);
628+
} else {
629+
context.put(prefix + tagName, new JSONArray());
630+
}
631+
} else {
632+
if (nilAttributeFound) {
633+
context.accumulate(prefix + tagName, JSONObject.NULL);
634+
} else if (jsonObject.length() > 0) {
635+
context.accumulate(prefix + tagName, jsonObject);
636+
} else {
637+
context.accumulate(prefix + tagName, "");
638+
}
639+
}
640+
return false;
641+
642+
} else if (token == GT) {
643+
// Content, between <...> and </...>
644+
for (;;) {
645+
token = x.nextContent();
646+
if (token == null) {
647+
if (tagName != null) {
648+
throw x.syntaxError("Unclosed tag " + tagName);
649+
}
650+
return false;
651+
} else if (token instanceof String) {
652+
string = (String) token;
653+
if (string.length() > 0) {
654+
if(xmlXsiTypeConverter != null) {
655+
jsonObject.accumulate(config.getcDataTagName(),
656+
stringToValue(string, xmlXsiTypeConverter));
657+
} else {
658+
Object obj = stringToValue((String) token);
659+
if (obj instanceof Boolean) {
660+
jsonObject.accumulate(config.getcDataTagName(),
661+
config.isKeepBooleanAsString()
662+
? ((String) token)
663+
: obj);
664+
} else if (obj instanceof Number) {
665+
jsonObject.accumulate(config.getcDataTagName(),
666+
config.isKeepNumberAsString()
667+
? ((String) token)
668+
: obj);
669+
} else {
670+
jsonObject.accumulate(config.getcDataTagName(), stringToValue((String) token));
671+
}
672+
}
673+
}
674+
675+
} else if (token == LT) {
676+
// Nested element
677+
if (currentNestingDepth == config.getMaxNestingDepth()) {
678+
throw x.syntaxError("Maximum nesting depth of " + config.getMaxNestingDepth() + " reached");
679+
}
680+
681+
if (parse(x, jsonObject, tagName, prefix, config, currentNestingDepth + 1)) {
682+
if (config.getForceList().contains(tagName)) {
683+
// Force the value to be an array
684+
if (jsonObject.length() == 0) {
685+
context.put(tagName, new JSONArray());
686+
} else if (jsonObject.length() == 1
687+
&& jsonObject.opt(config.getcDataTagName()) != null) {
688+
context.append(prefix + tagName, jsonObject.opt(config.getcDataTagName()));
689+
} else {
690+
context.append(prefix + tagName, jsonObject);
691+
}
692+
} else {
693+
if (jsonObject.length() == 0) {
694+
context.accumulate(prefix + tagName, "");
695+
} else if (jsonObject.length() == 1
696+
&& jsonObject.opt(config.getcDataTagName()) != null) {
697+
context.accumulate(prefix + tagName, jsonObject.opt(config.getcDataTagName()));
698+
} else {
699+
if (!config.shouldTrimWhiteSpace()) {
700+
removeEmpty(jsonObject, config);
701+
}
702+
context.accumulate(prefix + tagName, jsonObject);
703+
}
704+
}
705+
706+
return false;
707+
}
708+
}
709+
}
710+
} else {
711+
throw x.syntaxError("Misshaped tag");
712+
}
713+
}
714+
}
715+
}
485716
/**
486717
* This method removes any JSON entry which has the key set by XMLParserConfiguration.cDataTagName
487718
* and contains whitespace as this is caused by whitespace between tags. See test XMLTest.testNestedWithWhitespaceTrimmingDisabled.
@@ -955,6 +1186,26 @@ public static JSONObject toJSONObject(Reader reader, JSONPointer path) throws JS
9551186
return result;
9561187
}
9571188

1189+
/**
1190+
* Given a customized function, convert the keys in the Json Object
1191+
* @param reader
1192+
* @param prefix
1193+
* @return
1194+
* @throws JSONException
1195+
*/
1196+
public static JSONObject toJSONObject(Reader reader, String prefix) throws JSONException {
1197+
JSONObject jo = new JSONObject();
1198+
XMLParserConfiguration config = XMLParserConfiguration.ORIGINAL;
1199+
XMLTokener x = new XMLTokener(reader, config);
1200+
while (x.more()) {
1201+
x.skipPast("<");
1202+
if(x.more()) {
1203+
parse(x, jo, null, prefix, config, 0);
1204+
}
1205+
}
1206+
return jo;
1207+
}
1208+
9581209
/**
9591210
* Helper method: skip the current element and its entire subtree without
9601211
* building any JSON output.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package org.json.junit.milestone3.tests;
2+
3+
import org.json.JSONException;
4+
import org.json.JSONObject;
5+
import org.json.JSONPointer;
6+
import org.json.XML;
7+
import org.junit.Test;
8+
9+
import java.io.StringReader;
10+
11+
import static org.junit.Assert.assertEquals;
12+
13+
public class XMLKeyTransformerTest {
14+
// define some customized functions for testing
15+
16+
@Test
17+
public void testXML01() {
18+
String xml = "<book><title><content>Old Title</content></title><author>John</author></book>";
19+
StringReader reader = new StringReader(xml);
20+
21+
JSONObject result = XML.toJSONObject(reader, "swe_262p");
22+
23+
System.out.println(result);
24+
}
25+
26+
@Test
27+
public void testXML02() {
28+
String xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+
29+
"<contact>\n"+
30+
" <nick>Crista </nick>\n"+
31+
" <name>Crista Lopes</name>\n" +
32+
" <address>\n" +
33+
" <street>Ave of Nowhere</street>\n" +
34+
" <zipcode>92614</zipcode>\n" +
35+
" </address>\n" +
36+
"</contact>";
37+
38+
try {
39+
JSONObject jobj = XML.toJSONObject(new StringReader(xmlString), "swe_262p");
40+
System.out.println(jobj);
41+
} catch (JSONException e) {
42+
System.out.println(e);
43+
}
44+
}
45+
}
46+
47+

0 commit comments

Comments
 (0)