Browse Source

HPCC-9085 Fix Roxie JSON handling of array item names

Simple arrays (ECL Sets) will no longer output names for items in
the array.  Also nested children with same name as array ancestor
will not be treated as array items.

Signed-off-by: Anthony Fishbeck <Anthony.Fishbeck@lexisnexis.com>
Anthony Fishbeck 12 years ago
parent
commit
64e2e61c16
2 changed files with 71 additions and 30 deletions
  1. 55 28
      common/thorhelper/thorxmlwrite.cpp
  2. 16 2
      common/thorhelper/thorxmlwrite.hpp

+ 55 - 28
common/thorhelper/thorxmlwrite.cpp

@@ -351,6 +351,36 @@ void CommonJsonWriter::checkDelimit(int inc)
     checkFormat(true, true, inc);
 }
 
+const char *CommonJsonWriter::checkItemName(CJsonWriterItem *item, const char *name)
+{
+    if (item && item->depth==0 && strieq(item->name, name))
+        return NULL;
+    return name;
+}
+
+const char *CommonJsonWriter::checkItemName(const char *name)
+{
+    CJsonWriterItem *item = (arrays.length()) ? &arrays.tos() : NULL;
+    return checkItemName(item, name);
+}
+
+const char *CommonJsonWriter::checkItemNameInc(const char *name)
+{
+    CJsonWriterItem *item = (arrays.length()) ? &arrays.tos() : NULL;
+    name = checkItemName(item, name);
+    if (item)
+        item->depth++;
+    return name;
+}
+
+const char *CommonJsonWriter::checkItemNameDec(const char *name)
+{
+    CJsonWriterItem *item = (arrays.length()) ? &arrays.tos() : NULL;
+    if (item)
+        item->depth--;
+    return checkItemName(item, name);
+}
+
 void CommonJsonWriter::outputQuoted(const char *text)
 {
     checkDelimit();
@@ -364,7 +394,7 @@ void CommonJsonWriter::outputString(unsigned len, const char *field, const char
     if ((flags & XWFopt) && (rtlTrimStrLen(len, field) == 0))
         return;
     checkDelimit();
-    appendJSONValue(out, fieldname, len, field);
+    appendJSONValue(out, checkItemName(fieldname), len, field);
 }
 
 void CommonJsonWriter::outputQString(unsigned len, const char *field, const char *fieldname)
@@ -382,43 +412,43 @@ void CommonJsonWriter::outputQString(unsigned len, const char *field, const char
 void CommonJsonWriter::outputBool(bool field, const char *fieldname)
 {
     checkDelimit();
-    appendJSONValue(out, fieldname, field);
+    appendJSONValue(out, checkItemName(fieldname), field);
 }
 
 void CommonJsonWriter::outputData(unsigned len, const void *field, const char *fieldname)
 {
     checkDelimit();
-    appendJSONValue(out, fieldname, len, field);
+    appendJSONValue(out, checkItemName(fieldname), len, field);
 }
 
 void CommonJsonWriter::outputInt(__int64 field, const char *fieldname)
 {
     checkDelimit();
-    appendJSONValue(out, fieldname, field);
+    appendJSONValue(out, checkItemName(fieldname), field);
 }
 
 void CommonJsonWriter::outputUInt(unsigned __int64 field, const char *fieldname)
 {
     checkDelimit();
-    appendJSONValue(out, fieldname, field);
+    appendJSONValue(out, checkItemName(fieldname), field);
 }
 
 void CommonJsonWriter::outputReal(double field, const char *fieldname)
 {
     checkDelimit();
-    appendJSONValue(out, fieldname, field);
+    appendJSONValue(out, checkItemName(fieldname), field);
 }
 
 void CommonJsonWriter::outputDecimal(const void *field, unsigned size, unsigned precision, const char *fieldname)
 {
     checkDelimit();
-    outputJsonDecimal(field, size, precision, fieldname, out);
+    outputJsonDecimal(field, size, precision, checkItemName(fieldname), out);
 }
 
 void CommonJsonWriter::outputUDecimal(const void *field, unsigned size, unsigned precision, const char *fieldname)
 {
     checkDelimit();
-    outputJsonUDecimal(field, size, precision, fieldname, out);
+    outputJsonUDecimal(field, size, precision, checkItemName(fieldname), out);
 }
 
 void CommonJsonWriter::outputUnicode(unsigned len, const UChar *field, const char *fieldname)
@@ -428,7 +458,7 @@ void CommonJsonWriter::outputUnicode(unsigned len, const UChar *field, const cha
     if ((flags & XWFopt) && (rtlTrimUnicodeStrLen(len, field) == 0))
         return;
     checkDelimit();
-    outputJsonUnicode(len, field, fieldname, out);
+    outputJsonUnicode(len, field, checkItemName(fieldname), out);
 }
 
 void CommonJsonWriter::outputUtf8(unsigned len, const char *field, const char *fieldname)
@@ -438,12 +468,12 @@ void CommonJsonWriter::outputUtf8(unsigned len, const char *field, const char *f
     if ((flags & XWFopt) && (rtlTrimUtf8StrLen(len, field) == 0))
         return;
     checkDelimit();
-    appendJSONValue(out, fieldname, len, field);
+    appendJSONValue(out, checkItemName(fieldname), len, field);
 }
 
 void CommonJsonWriter::outputBeginArray(const char *fieldname)
 {
-    arrays.append(fieldname);
+    arrays.append(*new CJsonWriterItem(fieldname));
     const char * sep = strchr(fieldname, '/');
     while (sep)
     {
@@ -471,24 +501,21 @@ void CommonJsonWriter::outputEndArray(const char *fieldname)
 
 void CommonJsonWriter::outputBeginNested(const char *fieldname, bool nestChildren)
 {
-    const char *parentArray = (arrays.length()) ? arrays.tos() : NULL;
-    if (parentArray && !streq(parentArray, fieldname))
-        parentArray = NULL;
     flush(false);
     checkFormat(true, false, 1);
-    const char * sep = (fieldname) ? strchr(fieldname, '/') : NULL;
-    while (sep)
+    fieldname = checkItemNameInc(fieldname);
+    if (fieldname)
     {
-        if (!parentArray)
+        const char * sep = (fieldname) ? strchr(fieldname, '/') : NULL;
+        while (sep)
         {
             StringAttr leading(fieldname, sep-fieldname);
             appendJSONName(out, leading).append("{");
+            fieldname = sep+1;
+            sep = strchr(fieldname, '/');
         }
-        fieldname = sep+1;
-        sep = strchr(fieldname, '/');
-    }
-    if (!parentArray)
         appendJSONName(out, fieldname);
+    }
     out.append("{");
     if (!nestChildren && !nestLimit)
         nestLimit = indent;
@@ -496,17 +523,17 @@ void CommonJsonWriter::outputBeginNested(const char *fieldname, bool nestChildre
 
 void CommonJsonWriter::outputEndNested(const char *fieldname)
 {
-    const char *parentArray = (arrays.length()) ? arrays.tos() : NULL;
-    if (parentArray && !streq(parentArray, fieldname))
-        parentArray = NULL;
     flush(false);
     checkFormat(false, true, -1);
-    const char * sep = (fieldname) ? strchr(fieldname, '/') : NULL;
-    while (sep)
+    fieldname = checkItemNameDec(fieldname);
+    if (fieldname)
     {
-        if (!parentArray)
+        const char * sep = (fieldname) ? strchr(fieldname, '/') : NULL;
+        while (sep)
+        {
             out.append('}');
-        sep = strchr(sep+1, '/');
+            sep = strchr(sep+1, '/');
+        }
     }
     out.append("}");
     if (indent==nestLimit)

+ 16 - 2
common/thorhelper/thorxmlwrite.hpp

@@ -122,9 +122,23 @@ protected:
             flusher->flushXML(out, isClose);
     }
 
-protected:
+    class CJsonWriterItem : public CInterface
+    {
+    public:
+        CJsonWriterItem(const char *_name) : name(_name), depth(0){}
+        IMPLEMENT_IINTERFACE;
+
+        StringAttr name;
+        unsigned depth;
+    };
+
+    const char *checkItemName(CJsonWriterItem *item, const char *name);
+    const char *checkItemName(const char *name);
+    const char *checkItemNameInc(const char *name);
+    const char *checkItemNameDec(const char *name);
+
     IXmlStreamFlusher *flusher;
-    StringArray arrays;
+    CIArrayOf<CJsonWriterItem> arrays;
     StringBuffer out;
     unsigned flags;
     unsigned indent;