Click here to Skip to main content
15,897,160 members
Articles / Artificial Intelligence

cn5apinet - ConceptNet5 API Library

Rate me:
Please Sign up or sign in to vote.
4.97/5 (6 votes)
28 Mar 2014GPL35 min read 45.7K   1.2K   19  
Connect to ConceptNet 5's REST API
/////////////////////////////////////////////////////////
// cn5apinet - ConceptNet Microsoft .NET API v1.9.0.0
// by Joseph P. Socoloski III 
// Copyright 2011. All Rights Reserved.
// NOTE:   Designed for ConceptNet5
// LIMITS:  - Work with downloaded json file [Can't too big throws memoryerrors]
// NEW :    - ConceptNet 5.1 API [Lookup, Search, and Association each produce difference return json]
//          - 
//LICENSE
//BY DOWNLOADING AND USING, YOU AGREE TO THE FOLLOWING TERMS:
//If it is your intent to use this software for non-commercial purposes, 
//such as in academic research, this software is free and is covered under 
//the GNU GPL License, given here: <http://www.gnu.org/licenses/gpl.txt> 
//You agree with 3RDPARTY's Terms Of Service 
//given here:   Json.NET Copyright (c) 2007 James Newton-King v4.0r2
//              http://james.newtonking.com/pages/json-net.aspx
// ConceptNet5  http://conceptnet5.media.mit.edu/
//              http://github.com/commonsense/conceptnet5/wiki
////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Collections;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.IO;
using System.Xml;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace cn5apinet
{
    #region enums
    public enum ReturnTYPE { assertion, concept, frame, frequency, raw_assertion, surface, leftfeature, rightfeature };
    public enum LANG { es, en, fr, hu, it, ja, ko, nl, pt };
    public enum DIRECTION { all, forward, backward };

    /*  Relational Ontology
        http://csc.media.mit.edu/docs/conceptnet/conceptnet4.html
        • Things: IsA, PartOf, HasProperty, DefinedAs, MadeOf, HasA
        • Spatial: LocatedNear, ObstructedBy, AtLocation
        • Events: HasSubevent, HasFirstSubevent, HasLastSubevent, HasPrerequisite, CreatedBy
        • Causal: Causes, CausesDesire
        • Affective: MotivatedByGoal, Desires
        • Functional: ReceivesAction, UsedFor, SymbolOf
        • Agents: CapableOf
    */

    /// <summary>
    /// Things about the object
    /// </summary>
    public enum Things
    {
        IsA, PartOf, HasProperty, DefinedAs, MadeOf, HasA
    };

    /// <summary>
    /// Spetial: Location Of object
    /// </summary>
    public enum Spatial
    {
        LocatedNear, ObstructedBy, AtLocation
    };

    /// <summary>
    /// Events explain any event related to the object.
    /// </summary>
    public enum Events
    {
        HasSubevent, HasFirstSubevent, HasLastSubevent, HasPrerequisite, CreatedBy
    };

    /// <summary>
    /// Causal: EffectOf, DesirousEffectOf
    /// </summary>
    public enum Causal
    {
        Causes, CausesDesire
    };

    /// <summary>
    /// Affective: MotivationOf, DesireOf
    /// (Drives of the object)
    /// </summary>
    public enum Affective
    {
        MotivatedByGoal, Desires
    };

    /// <summary>
    /// Functional: CapableOfReceivingAction, UsedFor
    /// </summary>
    public enum Functional
    {
        ReceivesAction, UsedFor, SymbolOf
    };

    /// <summary>
    /// Agents: CapableOf
    /// </summary>
    public enum Agents
    {
        CapableOf
    };
    #endregion enums

    #region ConceptNet Return Object
    /// <summary>
    /// Static variables related to Conceptnet5: API_URL, API_URLSEARCH, etc.
    /// </summary>
    public class Common
    {
        //public static string SERVER_URL = @"http://openmind.media.mit.edu";
        public static string API_URL = @"http://conceptnet5.media.mit.edu/data/5.1/c/";
        public static string API_URLSEARCH = @"http://conceptnet5.media.mit.edu/data/5.1/search?";
        public static string API_URLASSOCIATION = @"http://conceptnet5.media.mit.edu/data/5.1/assoc";
        public static string RESTDOC_URL = @"https://github.com/commonsense/conceptnet5/wiki/API";
        public static string CLIENT_VERSION = "1";
    }


    /// <summary>
    /// Lookup is for when you know the URI of an object in ConceptNet, 
    /// and want to see a list of edges that include it
    /// </summary>
    public class Lookup
    {
        public int numFound { get; set; }
        public object edges { get; set; }
        public float maxScore { get; set; }

        public List<edgeLookup> ToEdgeList()
        {
            List<edgeLookup> list = new List<edgeLookup>();

            JArray obj = JArray.FromObject(this.edges);
            foreach (object item in obj.Children())
            {
                edgeLookup sResult = new edgeLookup();
                sResult = JsonConvert.DeserializeObject<edgeLookup>(item.ToString());
                list.Add(sResult);
            }

            return list;
        }

        /// <summary>
        /// Get the raw pretty print string of this object.
        /// </summary>
        /// <returns>String, null if no value found</returns>
        public String PPrint()
        {
            if (this != null)
                return JsonConvert.SerializeObject(this, Newtonsoft.Json.Formatting.Indented);
            else
                return "null";
        }
    }

    /// <summary>
    /// These are the underlying edges used to implement the ConceptNet 5 hypergraph. 
    /// They are meant to be a small, closed class; you use them to express Assertions 
    /// involving the interesting open class of Relations.
    /// Ref: https://github.com/commonsense/conceptnet5/wiki/API
    /// Modified for CN5.1
    /// </summary>
    public class edgeLookup
    {
        public String endLemmas { get; set; }
        public String rel { get; set; }
        public String end { get; set; }
        public List<String> features { get; set; }
        public String license { get; set; }
        public List<String> sources { get; set; }
        public String startLemmas { get; set; }
        public List<String> text { get; set; }
        public String uri { get; set; }
        public float weight { get; set; }
        public String dataset { get; set; }
        public String start { get; set; }
        public float score { get; set; }
        public String context { get; set; }
        public String timestamp { get; set; }
        public List<String> nodes { get; set; }
        public String id { get; set; }
    }

    /// <summary>
    /// The base URL for searching is http://conceptnet5.media.mit.edu/data/5.1/search. 
    /// You add GET arguments to this to specify what to search for.
    /// {id, uri, rel, start, end, context, dataset, license}=URI: giving a ConceptNet URI for any of these parameters will return edges whose corresponding fields start with the given path.
    /// nodes=URI: returns edges whose rel, start, or end start with the given URI.
    /// {startLemmas, endLemmas, relLemmas}=word: returns edges containing the given lemmatized word anywhere in their start, end, or rel respectively.
    /// text=word: matches any of startLemmas, endLemmas, or relLemmas.
    /// surfaceText=word: matches edges with the given word in their surface text. The word is not lemmatized, but it is a case-insensitive match.
    /// minWeight=weight: filters for edges whose weight is at least weight.
    /// limit=n: change the number of results from the default of 50.
    /// offset=n: skip the first n results.
    /// features=str: Takes in a feature string (an assertion with one open slot), and returns edges having exactly that string as one of their features. Look at the features field of returned results for examples.
    /// filter=core|core-assertions: filter the returned results -- see "Filters" on the CN5 wiki.
    /// </summary>
    public class Search
    {
        public int numFound { get; set; }
        public object edges { get; set; }
        public float maxScore { get; set; }

        public List<edgeSearch> ToEdgeList()
        {
            List<edgeSearch> list = new List<edgeSearch>();

            JArray obj = JArray.FromObject(this.edges);
            foreach (object item in obj.Children())
            {
                edgeSearch sResult = new edgeSearch();
                sResult = JsonConvert.DeserializeObject<edgeSearch>(item.ToString());
                list.Add(sResult);
            }

            return list;
        }

        /// <summary>
        /// Get the raw pretty print string of this object.
        /// </summary>
        /// <returns>String, null if no value found</returns>
        public String PPrint()
        {
            if (this != null)
                return JsonConvert.SerializeObject(this, Newtonsoft.Json.Formatting.Indented);
            else
                return "null";
        }
    }

    /// <summary>
    /// pair object used to hold URIWord and a score.
    /// Used in Association.
    /// </summary>
    public class pair
    {
        public String URIWord { get; set; }
        public float score { get; set; }
    }

    /// <summary>
    /// These are the underlying edges used to implement the ConceptNet 5 hypergraph. 
    /// They are meant to be a small, closed class; you use them to express Assertions 
    /// involving the interesting open class of Relations.
    /// Ref: https://github.com/commonsense/conceptnet5/wiki/API
    /// Modified for CN5.1
    /// </summary>
    public class edgeSearch
    {
        public String endLemmas { get; set; }
        public String rel { get; set; }
        public String end { get; set; }
        public List<String> features { get; set; }
        public String license { get; set; }
        public List<String> sources { get; set; }
        public String startLemmas { get; set; }
        public List<String> text { get; set; }
        public String uri { get; set; }
        public float weight { get; set; }
        public String dataset { get; set; }
        public String start { get; set; }
        public float score { get; set; }
        public String context { get; set; }
        public String timestamp { get; set; }
        public List<String> nodes { get; set; }
        public String id { get; set; }
        public String surfaceText { get; set; }
    }

    #endregion ConceptNet Return Object

    /// <summary>
    /// The Main ConceptNet5 ReST Client
    /// https://github.com/commonsense/conceptnet5/wiki/API
    /// </summary>
    public class ConceptNetAPI
    {
        /// <summary>
        /// Used to build the full url before making the query to json server
        /// For CN5 it should be "http://conceptnet5.media.mit.edu/data/concept/"
        /// this can be found and changed in cn5apinet.Common.API_URL
        /// </summary>
        public string url_base { get; set; }

        /// <summary>
        /// ConceptNetAPI Object Client
        /// </summary>
        public ConceptNetAPI()
        {
            this.url_base = cn5apinet.Common.API_URL;
        }

        /// <summary>
        /// ConceptNetAPI Object Client
        /// </summary>
        /// <param name="api_baseurl">Overide CN5 url here [default: 'http://conceptnet5.media.mit.edu/data/concept/']</param>
        public ConceptNetAPI(string api_baseurl)
        {
            this.url_base = api_baseurl;
        }

        #region Public Statics
        /// <summary>
        /// Convert a query.xml to json (ConceptNet4)
        /// but will take any valid System.Xml.XmlDocument
        /// and convert it to json.
        /// </summary>
        /// <param name="xmldoc">XmlDocument</param>
        /// <returns>json string</returns>
        public static string ConvertToJSON(XmlDocument xmldoc)
        {
            try
            {
                return JsonConvert.SerializeXmlNode(xmldoc);
            }
            catch (Exception)
            {
                throw;
            }
        }

        #endregion Public Statics

        /// <summary>
        /// For testing purposes
        /// </summary>
        public void test()
        {
            //Newtonsoft.Json.Linq.JObject o = new JObject(File.ReadAllText("C:\\burnit\\conceptnet5-json\\nodes.json"));
            //JsonReader reader = new JsonReader(new InputStreamReader(instream, "UNICODE"));

            //while (reader.Read())
            //{
            //    Console.WriteLine(reader.TokenType + "tt" + WriteValue(reader.ValueType) + "tt" + WriteValue(reader.Value));
            //}


            String title = "";
        }

        /// <summary>
        /// Lookup is for when you know the URI of an object in ConceptNet, and want to see a list of edges that include it.
        /// </summary>
        /// <param name="language">language</param>
        /// <param name="concept_name">Expects entirely built suffix for url. For example, '/contributor/omcs/rspeer', 'toast?offset=5&limit=5', etc.</param>
        /// <returns>Lookup object</returns>
        public Lookup Lookup(LANG language, String concept_name)
        {
            Lookup searchResult = new cn5apinet.Lookup();
            string fullURL = "";
            //For some reason 'contributor' calls have a url http://conceptnet5.media.mit.edu/data/5.1/s/contributor/omcs/rspeer with no more 'c' it is 's' instead so change that
            if(concept_name.Contains(@"/contributor/"))
            {
                if(concept_name.StartsWith(@"/"))
                    concept_name = concept_name.Remove(0,1);
                fullURL = this.url_base.Replace(@"/c/", @"/s/") + concept_name;
            }
            else
                fullURL = this.url_base + language + "/" + concept_name;
            try
            {
                var request = WebRequest.Create(fullURL) as HttpWebRequest;
                request.UserAgent = "cnapinet sample";
                request.KeepAlive = false;
                request.Timeout = 15 * 1000;
                var response = request.GetResponse() as HttpWebResponse;
                if (request.HaveResponse == true && response != null)
                {
                    var reader = new StreamReader(response.GetResponseStream());
                    //Console.WriteLine(reader.ReadToEnd());
                    //string[] keyroot = new string[] {""};
                    string keyword = "";
                    if (concept_name.Contains('?'))
                    {
                        keyword = concept_name.Split('?')[0];
                    }
                    else
                        keyword = concept_name;


                    string outp = "{" + "json" + ": ";
                    outp += reader.ReadToEnd();
                    outp += "}";
                    ///string outp = "{json: {  \"numFound\": 847,   \"edges\": [    {      \"endLemmas\": \"drink consume alcohol\",       \"rel\": \"/r/Entails\",       \"end\": \"/c/en/drink/v/consume_alcohol\",       \"features\": [        \"/c/en/toast/v/propose_a_toast_to /r/Entails -\",         \"/c/en/toast/v/propose_a_toast_to - /c/en/drink/v/consume_alcohol\",         \"- /r/Entails /c/en/drink/v/consume_alcohol\"      ],       \"license\": \"/l/CC/By\",       \"sources\": [        \"/s/wordnet/3.0\"      ],       \"startLemmas\": \"toast propose toast to\",       \"text\": [        \"drink consume alcohol\",         \"toast propose toast to\"      ],       \"uri\": \"/a/[/r/Entails/,/c/en/toast/v/propose_a_toast_to/,/c/en/drink/v/consume_alcohol/]\",       \"weight\": 2.0,       \"dataset\": \"/d/wordnet/3.0\",       \"start\": \"/c/en/toast/v/propose_a_toast_to\",       \"score\": 10.605541000000001,       \"context\": \"/ctx/all\",       \"timestamp\": \"2012-05-25T01:27:09.75Z\",       \"nodes\": [        \"/c/en/drink/v/consume_alcohol\",         \"/c/en/toast/v/propose_a_toast_to\",         \"/r/Entails\"      ],       \"id\": \"/e/830e8a50011ee57aee04b92e846b31c11aebeda7\"    }],   \"maxScore\": 10.605541000000001}}";//test
                    ///string outp = "{json: {\"edges\": [    {      \"endLemmas\": \"drink consume alcohol\",       \"rel\": \"/r/Entails\",       \"end\": \"/c/en/drink/v/consume_alcohol\",       \"features\": [        \"/c/en/toast/v/propose_a_toast_to /r/Entails -\",         \"/c/en/toast/v/propose_a_toast_to - /c/en/drink/v/consume_alcohol\",         \"- /r/Entails /c/en/drink/v/consume_alcohol\"      ],       \"license\": \"/l/CC/By\",       \"sources\": [        \"/s/wordnet/3.0\"      ],       \"startLemmas\": \"toast propose toast to\",       \"text\": [        \"drink consume alcohol\",         \"toast propose toast to\"      ],       \"uri\": \"/a/[/r/Entails/,/c/en/toast/v/propose_a_toast_to/,/c/en/drink/v/consume_alcohol/]\",       \"weight\": 2.0,       \"dataset\": \"/d/wordnet/3.0\",       \"start\": \"/c/en/toast/v/propose_a_toast_to\",       \"score\": 10.605541000000001,       \"context\": \"/ctx/all\",       \"timestamp\": \"2012-05-25T01:27:09.75Z\",       \"nodes\": [        \"/c/en/drink/v/consume_alcohol\",         \"/c/en/toast/v/propose_a_toast_to\",         \"/r/Entails\"      ],       \"id\": \"/e/830e8a50011ee57aee04b92e846b31c11aebeda7\"    }] }}";
                    
                    JObject CNSearch = JObject.Parse(outp);
                    // get JSON result objects into a list
                    JToken results = CNSearch["json"];

                    // serialize JSON results into .NET objects
                    Lookup sResult = new Lookup();
                    sResult = JsonConvert.DeserializeObject<Lookup>(results.ToString());
                    //There are at least two 'types' found here 'web_concept' and 'concept'
                    string[] seperators = new string[] { "}," };
                    searchResult = sResult;

                }
            }
            catch (Exception ex)
            {
                //throw new Exception("Error fetching data.");
                Console.WriteLine("cnapinet Lookup_json: [" + ex.Message + "] Check for valid relationship key variable. URL=" + fullURL);
                if (ex.Message == "The remote server returned an error: (404) Not Found.")
                    searchResult.numFound = -1;
            }

            return searchResult;
        }

        /// <summary>
        /// Search finds a list of edges that match certain criteria.
        /// </summary>
        /// <param name="language">language</param>
        /// <param name="rel">relationship</param>
        /// <param name="start">start</param>
        /// <param name="end">end</param>
        /// <param name="text">text=word: matches any of startLemmas, endLemmas, or relLemmas.</param>
        /// <param name="limit">limit=n: change the number of results from the default of 50.</param>
        /// <returns>Search object</returns>
        public Search Search(LANG language, String rel, String start, String end, String text, int limit)
        {
            // http://conceptnet5.media.mit.edu/data/5.1/search?end=/c/en/car&rel=/r/PartOf&limit=10
            Search searchResult = new cn5apinet.Search();
            string fullURL = "";
            StringCollection scURL = new StringCollection();
            if (rel != "")
                scURL.Add(@"rel=/r/" + rel);
            if (start != "")
                scURL.Add(@"start=/c/"+language+"/" + start);
            if (end != "")
                scURL.Add(@"end=/c/" + language + "/" + end);
            if (limit != null || limit != -1)
                scURL.Add(@"limit=" + Convert.ToString(limit));
            if (text != "")
            {
                scURL.Clear();
                scURL.Add(@"text=" + text);
            }
            string urlEnd = "";
            int i = 0;
            foreach (string item in scURL)
            {
                if (i == 0)
                    urlEnd += item;
                else
                    urlEnd += "&" + item;
                    i = i + 1;
            }

            fullURL = Common.API_URLSEARCH + urlEnd;
            try
            {
                var request = WebRequest.Create(fullURL) as HttpWebRequest;
                request.UserAgent = "cnapinet sample";
                request.KeepAlive = false;
                request.Timeout = 15 * 1000;
                var response = request.GetResponse() as HttpWebResponse;
                if (request.HaveResponse == true && response != null)
                {
                    var reader = new StreamReader(response.GetResponseStream());
                    string outp = "{" + "json" + ": ";
                    outp += reader.ReadToEnd();
                    outp += "}";
 
                    JObject CNSearch = JObject.Parse(outp);
                    // get JSON result objects into a list
                    JToken results = CNSearch["json"];

                    // serialize JSON results into .NET objects
                    Search sResult = new Search();
                    sResult = JsonConvert.DeserializeObject<Search>(results.ToString());
                    //There are at least two 'types' found here 'web_concept' and 'concept'
                    string[] seperators = new string[] { "}," };
                    searchResult = sResult;

                }
            }
            catch (Exception ex)
            {
                //throw new Exception("Error fetching data.");
                Console.WriteLine("cnapinet Search_json: [" + ex.Message + "] Check for valid relationship key variable. URL=" + fullURL);
                if (ex.Message == "The remote server returned an error: (404) Not Found.")
                    searchResult.numFound = -1;
            }

            return searchResult;
        }

        /// <summary>
        /// Association is for finding concepts similar to a particular concept or a list of concepts.
        /// </summary>
        /// <param name="language">language</param>
        /// <param name="word">If you wish multi, start with use ',' between each word. ie: 'toast,cereal,juice,egg'.</param>
        /// <param name="filter">filter=URI: return only results that start with the given URI. For example, filter=/c/en returns results in English.</param>
        /// <param name="limit">limit=n: change the number of results from the default of 10.</param>
        /// <param name="multipleterms">If true, then expecting a list like 'toast,cereal,juice,egg' etc.</param>
        /// <returns>Association object</returns>
        public Association Associations(LANG language, String word, String filter, int limit, bool multipleterms, int weight)
        {
            Association searchResult = new cn5apinet.Association();
            string fullURL = "";
            StringCollection scURL = new StringCollection();
            if (word != "")
            {
                if(!word.Contains(','))
                    scURL.Add("/c/" + language + "/" + word);
                else
                    scURL.Add("/list/" + language + "/" + word);
            }
            if (filter != "")
            {
                //This filter item needs to be in this position to be successfull; eg: http://conceptnet5.media.mit.edu/data/5.1/assoc/c/en/cat?filter=/c/en/dog&limit=1
                if (filter != "en")
                    scURL.Add("filter=/c/" + language + "/" + filter);
            }
            if (weight != 0 && multipleterms)
                scURL.Add("@" + Convert.ToString(weight));
            if (limit != 0 && limit != -1)
                scURL.Add(@"limit=" + Convert.ToString(limit));
            if (filter != "")
            {
                //This filter item needs to be in this position to be successfull; eg: http://conceptnet5.media.mit.edu/data/5.1/assoc/list/en/happy,sad@-1?limit=20&filter=/c/en
                if (filter == "en")
                    scURL.Add("filter=/c/" + language);
            }

            string urlEnd = "";
            int i = 0;
            foreach (string item in scURL)
            {
                if (i == 0)
                    urlEnd += item;
                else
                {
                    if ((item.Contains("limit=")) && (!multipleterms))
                    {
                        urlEnd += "&" + item;
                    }
                    else if ((item.Contains("filter=")) && (multipleterms))
                    {
                        urlEnd += "&" + item;
                    }
                    else
                    {
                        if (!item.StartsWith("@"))
                            urlEnd += "?" + item;
                        else
                        {
                            //this is a @-1 value so only skip it if it has a 0 value
                            if(item != "@0")
                                urlEnd += item;
                        }
                    }
                }
                i = i + 1;
            }
            //http://conceptnet5.media.mit.edu/data/5.1/assoc/list/en/happy,sad@-1?limit=25?filter=/c/en
            fullURL = Common.API_URLASSOCIATION + urlEnd;
            try
            {
                var request = WebRequest.Create(fullURL) as HttpWebRequest;
                request.UserAgent = "cnapinet sample";
                request.KeepAlive = false;
                request.Timeout = 15 * 1000;
                var response = request.GetResponse() as HttpWebResponse;
                if (request.HaveResponse == true && response != null)
                {
                    var reader = new StreamReader(response.GetResponseStream());
                    string outp = "{" + "json" + ": ";
                    outp += reader.ReadToEnd();
                    outp += "}";

                    JObject CNSearch = JObject.Parse(outp);
                    // get JSON result objects into a list
                    JToken results = CNSearch["json"];

                    // serialize JSON results into .NET objects
                    Association sResult = new Association();
                    sResult = JsonConvert.DeserializeObject<Association>(results.ToString());
                    //There are at least two 'types' found here 'web_concept' and 'concept'
                    string[] seperators = new string[] { "}," };
                    searchResult = sResult;

                }
            }
            catch (Exception ex)
            {
                //throw new Exception("Error fetching data.");
                Console.WriteLine("cnapinet Search_json: [" + ex.Message + "] Check for valid relationship key variable. URL=" + fullURL);
            }

            return searchResult;
        }
    }

    /// <summary>
    ///The base URL is http://conceptnet5.media.mit.edu/data/5.1/assoc . This URL can be followed by:
    ///A concept URI, in which case it will show you the most similar concepts to that concept.
    ///A path of the form /list/[language]/[term list], which finds the most similar concepts to a list of terms, as described below.
    ///You can set the following GET arguments to modify the returned results:
    ///limit=n: change the number of results from the default of 10.
    ///filter=URI: return only results that start with the given URI. For example, filter=/c/en returns results in English.
    /// </summary>
    public class Association
    {
        public object terms { get; set; }
        public object similar { get; set; }

        public List<pair> ToEdgeList()
        {
            List<pair> list = new List<pair>();

            if (this.similar != null)
            {
                JArray obj = JArray.FromObject(this.similar);
                foreach (object item in obj.Children())
                {
                    string[] splitter = Convert.ToString(item).Replace("[", "").Replace("\r\n", "").Replace("\"", "").Replace("]", "").Split(',');
                    pair Pair = new pair();
                    Pair.URIWord = splitter[0].Trim();

                    if (splitter.Length == 2)
                    {
                        Pair.score = float.Parse(splitter[1].Trim());
                    }
                    else
                    {
                        Pair.score = float.Parse(splitter[splitter.Length-1].Trim());
                    }

                    list.Add(Pair);
                }
            }

            return list;
        }

        /// <summary>
        /// Get the raw pretty print string of this object.
        /// </summary>
        /// <returns>String, null if no value found</returns>
        public String PPrint()
        {
            if (this != null)
                return JsonConvert.SerializeObject(this, Newtonsoft.Json.Formatting.Indented);
            else
                return "null";
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Chief Technology Officer Earthbotics.com
United States United States
Born in Pennsylvania (USA), just north of Philadelphia. Joe has been programming since he was ten[now much older]. He is entirely self-taught programmer, & he is currently working as an IT Manager in Seattle WA. He was previously U.S. Navy Active Reservist for (SPAWAR)
In '98 was honorably discharged from the USN. He served onboard the USS Carl Vinson (94-98) He was lucky enough to drink President Clinton's leftover wine, promoted by his Captain, and flew in a plane off the flightdeck but not all at the same time. His interests, when time allows, are developing
misc apps and Artificial Intelligence proof-of-concept demos that specifically exhibits human behavior. He is a true sports-a-holic, needs plenty of caffeine, & a coding junkie. He also enjoys alternative music and a big Pearl Jam, Nirvana, new alternative music fan, and the Alison Wonderland.
He is currently working on earthboticsai.net<> which he says is fun and cool. Cool | :cool: :cheers:

Joe is an INTP[
^] personality type. Joe "sees everything in terms of how it could be improved, or what it could be turned into. INTP's live primarily inside their own minds." INTPs also can have the "greatest precision in thought and language. Can readily discern contradictions and inconsistencies. The world exists primarily to be understood. 1% of the total population" [

Comments and Discussions