@@ -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.
0 commit comments