private static void propertyWalk(IElement root,
 JSONObject properties, JSONArray children)
   {
       string[] className=getClassNames(root);
       if(className.Length>0){
         IList<string> types=new List<string>();
         bool hasProperties=false;
         foreach(var cls in className){
       if(cls.StartsWith("p-",StringComparison.Ordinal) && properties!=null){
         hasProperties=true;
       } else if(cls.StartsWith("u-",StringComparison.Ordinal) && properties!=null){
         hasProperties=true;
       } else if(cls.StartsWith("dt-",StringComparison.Ordinal) && properties!=null){
         hasProperties=true;
       } else if(cls.StartsWith("e-",StringComparison.Ordinal) && properties!=null){
         hasProperties=true;
       } else if(cls.StartsWith("h-",StringComparison.Ordinal)){
         types.Add(cls);
       }
         }
         if(types.Count==0 && hasProperties){
       // has properties and isn't a microformat
       // root
       foreach(var cls in className){
         if(cls.StartsWith("p-",StringComparison.Ordinal)){
       string value=getPValue(root);
       if(!StringUtility.isNullOrSpaces(value)) {
         accumulateValue(properties,cls.Substring(2),value);
       }
         } else if(cls.StartsWith("u-",StringComparison.Ordinal)){
       accumulateValue(properties,cls.Substring(2),
           getUValue(root));
         } else if(cls.StartsWith("dt-",StringComparison.Ordinal)){
       accumulateValue(properties,cls.Substring(3),
           getDTValue(root,getLastKnownTime(properties)));
         } else if(cls.StartsWith("e-",StringComparison.Ordinal)){
       accumulateValue(properties,cls.Substring(2),
           getEValue(root));
         }
       }
         } else if(types.Count>0){
       // this is a child microformat
       // with no properties
       JSONObject obj=new JSONObject();
       obj.put("type", new JSONArray(types));
       // for holding child elements with
       // properties
       JSONObject subProperties=new JSONObject();
       // for holding child microformats with no
       // property class
       JSONArray subChildren=new JSONArray();
       foreach(var child in root.getChildNodes()){
         if(child is IElement) {
       propertyWalk((IElement)child,
           subProperties,subChildren);
         }
       }
       if(subChildren.Length>0){
         obj.put("children", subChildren);
       }
       if(types.Count>0){
         // we imply missing properties here
         // Imply p-name and p-url
         if(!implyForLink(root,subProperties)){
       if(hasSingleChildElementNamed(root,"a")){
         implyForLink(getFirstChildElement(root),subProperties);
       } else {
         string pvalue=getPValue(root);
         if(!StringUtility.isNullOrSpaces(pvalue)) {
           setValueIfAbsent(subProperties,"name", pvalue);
         }
       }
         }
         // Also imply u-photo
         if(StringUtility.toLowerCaseAscii(root.getLocalName()).Equals("img") &&
         root.getAttribute("src")!=null){
       setValueIfAbsent(subProperties,"photo", getUValue(root));
         }
         if(!subProperties.has("photo")){
       IList<IElement> images=root.getElementsByTagName("img");
       // If there is only one descendant image, imply
       // u-photo
       if(images.Count==1){
         setValueIfAbsent(subProperties,"photo",
             getUValue(images[0]));
       }
         }
       }
       obj.put("properties", subProperties);
       if(hasProperties){
         foreach(var cls in className){
       if(cls.StartsWith("p-",StringComparison.Ordinal)){ // property
         JSONObject clone=copyJson(obj);
         clone.put("value",getPValue(root));
         accumulateValue(properties,cls.Substring(2),clone);
       } else if(cls.StartsWith("u-",StringComparison.Ordinal)){ // URL
         JSONObject clone=copyJson(obj);
         clone.put("value",getUValue(root));
         accumulateValue(properties,cls.Substring(2),clone);
       } else if(cls.StartsWith("dt-",StringComparison.Ordinal)){ // date/time
         JSONObject clone=copyJson(obj);
         clone.put("value",getDTValue(root,getLastKnownTime(properties)));
         accumulateValue(properties,cls.Substring(3),clone);
       } else if(cls.StartsWith("e-",StringComparison.Ordinal)){ // date/time
         JSONObject clone=copyJson(obj);
         clone.put("value",getEValue(root));
         accumulateValue(properties,cls.Substring(2),clone);
       }
         }
       } else {
         children.put(obj);
       }
       return;
         }
       }
       foreach(var child in root.getChildNodes()){
         if(child is IElement) {
       propertyWalk((IElement)child,properties,children);
         }
       }
   }
 private static void accumulateValue(JSONObject obj, string key, Object value)
 {
     JSONArray arr=null;
     if(obj.has(key)){
       arr=obj.getJSONArray(key);
     } else {
       arr=new JSONArray();
       obj.put(key, arr);
     }
     arr.put(value);
 }
 /**
    *
    * Scans an HTML element for Microformats.org metadata.
    * The resulting _object will contain an "items" property,
    * an array of all Microformats items.  Each item will
    * have a "type" and "properties" properties.
    *
    * @param root the element to scan.
    * @return a JSON _object containing Microformats metadata
    */
 public static JSONObject getMicroformatsJSON(IElement root)
 {
     if((root)==null)throw new ArgumentNullException("root");
     JSONObject obj=new JSONObject();
     JSONArray items=new JSONArray();
     propertyWalk(root,null,items);
     obj.put("items", items);
     return obj;
 }
 public static JSONObject getRelJSON(IElement root)
 {
     if((root)==null)throw new ArgumentNullException("root");
     JSONObject obj=new JSONObject();
     JSONArray items=new JSONArray();
     JSONObject item=new JSONObject();
     accumulateValue(item,"type","rel");
     JSONObject props=new JSONObject();
     relWalk(root,props);
     item.put("properties", props);
     items.put(item);
     obj.put("items", items);
     return obj;
 }
 private static void setValueIfAbsent(JSONObject obj, string key, Object value)
 {
     if(!obj.has(key)){
       JSONArray arr=null;
       arr=new JSONArray();
       obj.put(key, arr);
       arr.put(value);
     }
 }
 public static Object patch(Object o, JSONArray patch)
 {
     // clone the _object in case of failure
     o=cloneJsonObject(o);
     for(int i=0;i<patch.Length;i++){
       Object op=patch[i];
       if(!(op is JSONObject))
     throw new ArgumentException("patch");
       if(o==null)
     throw new InvalidOperationException("patch");
       JSONObject patchOp=(JSONObject)op;
       // NOTE: This algorithm requires "op" to exist
       // only once; the JSONObject, however, does not
       // allow duplicates
       string opStr=getString(patchOp,"op");
       if(opStr==null)
     throw new ArgumentException("patch");
       if("add".Equals(opStr)){
     // operation
     Object value=null;
     try {
       value=patchOp["value"];
     } catch(System.Collections.Generic.KeyNotFoundException){
       throw new ArgumentException("patch "+opStr+" value");
     }
     o=addOperation(o,opStr,getString(patchOp,"path"),value);
       } else if("replace".Equals(opStr)){
     // operation
     Object value=null;
     try {
       value=patchOp["value"];
     } catch(System.Collections.Generic.KeyNotFoundException){
       throw new ArgumentException("patch "+opStr+" value");
     }
     o=replaceOperation(o,opStr,getString(patchOp,"path"),value);
       } else if("remove".Equals(opStr)){
     // Remove operation
     string path=patchOp.getString("path");
     if(path==null)throw new ArgumentException("patch "+opStr+" path");
     if(path.Length==0) {
       o=null;
     } else {
       removeOperation(o,opStr,getString(patchOp,"path"));
     }
       } else if("move".Equals(opStr)){
     string path=patchOp.getString("path");
     if(path==null)throw new ArgumentException("patch "+opStr+" path");
     string fromPath=patchOp.getString("from");
     if(fromPath==null)throw new ArgumentException("patch "+opStr+" from");
     if(path.StartsWith(fromPath,StringComparison.Ordinal))
       throw new ArgumentException("patch "+opStr);
     Object movedObj=removeOperation(o,opStr,fromPath);
     o=addOperation(o,opStr,path,cloneJsonObject(movedObj));
       } else if("copy".Equals(opStr)){
     string path=patchOp.getString("path");
     if(path==null)throw new ArgumentException("patch "+opStr+" path");
     string fromPath=patchOp.getString("from");
     if(fromPath==null)throw new ArgumentException("patch "+opStr+" from");
     JSONPointer pointer=JSONPointer.fromPointer(o, path);
     if(!pointer.exists())
       throw new System.Collections.Generic.KeyNotFoundException("patch "+opStr+" "+fromPath);
     Object copiedObj=pointer.getValue();
     o=addOperation(o,opStr,path,cloneJsonObject(copiedObj));
       } else if("test".Equals(opStr)){
     string path=patchOp.getString("path");
     if(path==null)throw new ArgumentException("patch "+opStr+" path");
     Object value=null;
     try {
       value=patchOp["value"];
     } catch(System.Collections.Generic.KeyNotFoundException){
       throw new ArgumentException("patch "+opStr+" value");
     }
     JSONPointer pointer=JSONPointer.fromPointer(o, path);
     if(!pointer.exists())
       throw new System.Collections.Generic.KeyNotFoundException("patch "+opStr+" "+path);
     Object testedObj=pointer.getValue();
     if((testedObj==null) ? (value!=null) : !testedObj.Equals(value))
       throw new InvalidOperationException("patch "+opStr);
       }
     }
     return (o==null) ? JSONObject.NULL : o;
 }
 public void writeObjectToStream(CacheControl o, Stream stream)
 {
     JSONObject jsonobj=new JSONObject();
       jsonobj.put("cacheability",o.cacheability);
       jsonobj.put("noStore",o.noStore);
       jsonobj.put("noTransform",o.noTransform);
       jsonobj.put("mustRevalidate",o.mustRevalidate);
       jsonobj.put("requestTime",Convert.ToString(o.requestTime,CultureInfo.InvariantCulture));
       jsonobj.put("responseTime",Convert.ToString(o.responseTime,CultureInfo.InvariantCulture));
       jsonobj.put("maxAge",Convert.ToString(o.maxAge,CultureInfo.InvariantCulture));
       jsonobj.put("date",Convert.ToString(o.date,CultureInfo.InvariantCulture));
       jsonobj.put("uri",o.uri);
       jsonobj.put("requestMethod",o.requestMethod);
       jsonobj.put("code",o.code);
       jsonobj.put("age",Convert.ToString(o.age,CultureInfo.InvariantCulture));
       JSONArray jsonarr=new JSONArray();
       foreach(var header in o.headers){
     jsonarr.put(header);
       }
       jsonobj.put("headers",jsonarr);
       StreamUtility.stringToStream(jsonobj.ToString(),stream);
 }
 /**
    * Produce a JSONObject by combining a JSONArray of names with the values
    * of this JSONArray.
    * @param names A JSONArray containing a list of key strings. These will be
    * paired with the values.
    * @return A JSONObject, or null if there are no names or if this JSONArray
    * has no values.
    */
 public JSONObject toJSONObject(JSONArray names)
 {
     if (names == null || names.Length == 0 || length() == 0)
       return null;
     JSONObject jo = new JSONObject();
     for (int i = 0; i < names.Length; i += 1) {
       jo.put(names.getString(i), opt(i));
     }
     return jo;
 }
 /**
    * Produce a JSONArray containing the values of the members of this
    * JSONObject.
    * @param names A JSONArray containing a list of key strings. This
    * determines the sequence of the values in the result.
    * @return A JSONArray of values.
    */
 public JSONArray toJSONArray(JSONArray names)
 {
     if (names == null || names.Length == 0)
       return null;
     JSONArray ja = new JSONArray();
     for (int i = 0; i < names.Length; i += 1) {
       ja.put(opt(names.getString(i)));
     }
     return ja;
 }
 /**
    * Produce a JSONArray containing the names of the elements of this
    * JSONObject.
    * @return A JSONArray containing the key strings, or null if the JSONObject
    * is empty.
    */
 public JSONArray names()
 {
     JSONArray ja = new JSONArray();
     foreach(var key in keys()) {
       ja.put(key);
     }
     if (ja.Length == 0)
       return null;
     return ja;
 }
 /**
    * Accumulate values under a key. It is similar to the put method except
    * that if there is already an _object stored under the key then a
    * JSONArray is stored under the key to hold all of the accumulated values.
    * If there is already a JSONArray, then the new value is appended to it.
    * In contrast, the put method replaces the previous value.
    *
    * @param key   A key _string.
    * @param value An _object to be accumulated under the key.
    * @return this.
    * @ if the key is null
    */
 public JSONObject accumulate(string key, Object value)
 {
     JSONArray a;
     Object o = opt(key);
     if (o == null) {
       put(key, value);
     } else if (o is JSONArray) {
       a = (JSONArray)o;
       a.put(value);
     } else {
       a = new JSONArray();
       a.put(o);
       a.put(value);
       put(key, a);
     }
     return this;
 }
 public static void main(string[] args)
 {
     string json="["+
     "{ # foo\n\"foo-key\":\"foo-value\"},\n"+
     "{ /* This is a\n # multiline comment.*/\n\"bar-key\":\"bar-value\"}]";
     Console.WriteLine(json);
       JSONArray obj=new JSONArray(json,
       JSONObject.OPTION_SHELL_COMMENTS | // Support SHELL-style comments
       JSONObject.OPTION_ADD_COMMENTS // Incorporate comments in the JSON _object
       );
       Console.WriteLine(obj); // Output the JSON _object
     // Objects with comments associated with them will
     // now contain a "@comment" key; get the JSON Pointers
     // (RFC6901) to these objects and remove the "@comment" keys.
     IDictionary<string,Object> pointers=JSONPointer.getPointersWithKeyAndRemove(obj,"@comment");
     // For each JSON Pointer, get its corresponding _object.
     // They will always be JSONObjects.
     foreach(var pointer in pointers.Keys){
       JSONObject subobj=(JSONObject)JSONPointer.getObject(obj,pointer);
       Console.WriteLine(subobj); // Output the _object
       Console.WriteLine(pointers[pointer]); // Output the key's value
     }
 }