home *** CD-ROM | disk | FTP | other *** search
/ Freelog 100 / FreelogNo100-NovembreDecembre2010.iso / Multimedia / Songbird / Songbird_1.8.0-1800_windows-i686-msvc8.exe / jsmodules / RDFHelper.jsm < prev    next >
Text File  |  2010-08-30  |  7KB  |  193 lines

  1. /**
  2.  * RDFHelper.jsm
  3.  * 
  4.  * USE: RDFHelper(aRdf, aRDFDatasource, aRDFResource, aNamespacesHash)
  5.  * 
  6.  * This class allows you to treat an RDF datasource as though it were a read-only structured object.
  7.  * (Please, don't try to write to it. It will only lead to grief.)
  8.  * 
  9.  * Arcs are mapped to properties by trimming their namespaces (they can be reduced to prefixes if you prefer).
  10.  * Because there may be several arcs leading from a resource, each property is returned as an array of the targets.
  11.  * Literals become values directly, and all other arcs lead to further arcs.
  12.  * 
  13.  * STATIC RDF SOURCE:
  14.  * The RDFHelper is not so clever as to notice changes to your datasource after it creates the value.
  15.  * As a result, you should not reuse RDFHelpers unless you are sure your data has not changed in-between.
  16.  * 
  17.  * CYCLIC RELATIONSHIPS:
  18.  * Links are evaluated lazily, so creating an RDFHelper object on a cyclic graph will not kill your process,
  19.  * but trying to crawl it probably will! Objects are not reused, so if you return to the same place twice, you
  20.  * won't be able to tell through naive object comparison, and infinitely traversing a graph cycle will be a race 
  21.  * between overflowing your stack and eating all your memory. 
  22.  * 
  23.  * CONTAINERS:
  24.  * Containers are a special case where the object returned appears to be array-like, insofar as it has numeric
  25.  * indices and a .length property, but is not actually an instanceof Array.
  26.  * 
  27.  * HELP:
  28.  * Because looking up RDF resources is tedious and unpleasant, a few helper bits are provided.
  29.  * 
  30.  *   RDFHelper.help:
  31.  *     Accepts URI strings representing a datasource, a resource, and an object containing namespaces.
  32.  *     namespaces look like: { "rdf:/namespace/prefix/whatever": "prefix_", "trimmed-prefix": "" }
  33.  *     EXAMPLE: RDFHelper.help("rdf:addon-metadata", "urn:songbird:addon:root", RDFHelper.prototype.DEFAULT_RDF_NAMESPACES);
  34.  * 
  35.  *   RDFHelper.DEFAULT_RDF_NAMESPACES{_PREFIXED}:
  36.  *     For convenience, provides rdf, mozilla, and songbird namespace objects that translate namespaces into object property prefixes.
  37.  *     With _PREFIXED, your properties will begin with rdf_, moz_ or sb_. Without, namespaces will simply be removed.
  38.  *     If you are concerned about collisions, be sure to map only one prefix to "".
  39.  * 
  40.  * USAGE EXAMPLE:
  41.  * 
  42.  * get the first display pane from the first addon and copy its properties into the "info" object. 
  43.  * 
  44.  * var addons = RDFHelper.help("rdf:addon-metadata", "urn:songbird:addon:root", RDFHelper.prototype.DEFAULT_RDF_NAMESPACES);
  45.  * if (addons[0].displayPanes && addons[0].displayPanes[0].displayPane[0]) {
  46.  *   var pane = addons[0].displayPanes[0].displayPane[0]
  47.  *   var info = {};
  48.  *   for (property in pane) {
  49.  *     if (pane[property])
  50.  *      info[property] = pane[property][0];
  51.  *   }
  52.  * }
  53.  */
  54.  
  55. EXPORTED_SYMBOLS = [ "RDFHelper" ];
  56.  
  57. Ci = Components.interfaces;
  58. Cc = Components.classes;
  59.  
  60. // make a constructor
  61. function RDFHelper(aRdf, aDatasource, aResource, aNamespaces) {
  62.   // this is a Crockfordian constructor with private methods.
  63.   // see: http://www.crockford.com/javascript/private.html
  64.   // the actual construction logic takes place after all these method def'ns.
  65.   // this enables me to hide these methods from the outside world so that
  66.   // users of the class can iterate over properties without seeing them.
  67.   var that = this; // for use in private functions
  68.   this.Value = aResource.Value; // TODO: is this Good Enough?
  69.   
  70.   _containerUtils = Cc["@mozilla.org/rdf/container-utils;1"]
  71.                      .getService(Ci.nsIRDFContainerUtils);
  72.   
  73.   var createProperties = function() {
  74.     //dump("Resource "+that._resource.Value+" is a ")
  75.     if (_containerUtils.IsContainer(aDatasource, aResource)) {
  76.       //dump("container.\n");
  77.       createContainerProperties(aResource);
  78.     }
  79.     else {
  80.       //dump("normal resource.\n");
  81.       createStandardProperties(aResource);
  82.     }
  83.   };
  84.   
  85.   var createContainerProperties = function(resource) {
  86.     var container = _containerUtils.MakeSeq(aDatasource, resource);
  87.     var contents = container.GetElements();
  88.     
  89.     // urgh, this doesn't actually mean "this" is an array 
  90.     // but at least it's sort of like one.
  91.     var i = 0;
  92.     while (contents.hasMoreElements()) {
  93.       var resource = contents.getNext()
  94.       resource.QueryInterface(Ci.nsIRDFResource);
  95.       that[i] = new RDFHelper(
  96.         aRdf, 
  97.         aDatasource, 
  98.         resource, 
  99.         aNamespaces
  100.       ); 
  101.       i++;
  102.     }
  103.     that.length = i;
  104.   };
  105.   
  106.   var createStandardProperties = function(resource) {
  107.     var labels = aDatasource.ArcLabelsOut(aResource);
  108.     while(labels.hasMoreElements()) {
  109.       var arc = labels.getNext().QueryInterface(Ci.nsIRDFResource)
  110.       createStandardProperty(arc);
  111.     }
  112.   };
  113.   
  114.   var createStandardProperty = function(arc) {
  115.     var alias = arc.Value;
  116.     for (n in aNamespaces) {
  117.        alias = alias.replace(n, aNamespaces[n]);
  118.     }
  119.     
  120.     //dump("Arc "+arc.Value+" is a normal prop aliased to "+alias+".\n")
  121.     
  122.     // define a little get-result function
  123.     // this lets us lazily evaluate resource links so that we don't
  124.     // descend into infinite recursion unless we work at it and try
  125.     // to depth-first search a cyclical graph or something
  126.     var getResult = function() {
  127.       ary = [];
  128.       var itr = aDatasource.GetTargets(aResource, arc, true);
  129.       while(itr.hasMoreElements()) {
  130.         var resource = itr.getNext();
  131.         if (resource instanceof Ci.nsIRDFLiteral) {
  132.           //dump(resource.Value + "is a literal property for "+alias+".\n");
  133.           ary.push(resource.Value);
  134.         }
  135.         else {
  136.           //dump(resource.Value + " inserted an RDF property.\n");
  137.           ary.push(new RDFHelper(
  138.             aRdf, 
  139.             aDatasource, 
  140.             resource, 
  141.             aNamespaces
  142.           ));
  143.         }
  144.       } 
  145.       // this turns out to be a really horrible idea if you want to write nice 
  146.       // code.
  147.       // but it's a nice idea and i'd like to talk to someone about whether or
  148.       // not it's worth salvaging (pvh jan08) 
  149.       /*if (ary.length == 1) {
  150.         ary = ary[0];
  151.       }*/
  152.       
  153.       // memoize the result to avoid n^2 iterations
  154.       delete that[alias];
  155.       that[alias] = ary;
  156.       return ary;
  157.     }
  158.     
  159.     that.__defineGetter__(alias, getResult);
  160.     // TODO: do i really want to keep the original name?
  161.     // i mean, really? it really ruins for (i in obj) syntax.
  162.     /*if (alias != arc.Value) {
  163.       that.__defineGetter__(arc.Value, getResult);
  164.     }*/
  165.   };
  166.   
  167.   createProperties();
  168. }
  169.  
  170. RDFHelper.help = function(datasource, resource, namespaces) {
  171.   // look up the initial values from the input strings.
  172.   var rdf = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
  173.   var helper = new RDFHelper(
  174.     rdf, 
  175.     rdf.GetDataSourceBlocking(datasource), 
  176.     rdf.GetResource(resource),
  177.     namespaces
  178.   );
  179.   return helper;
  180. };
  181.  
  182. RDFHelper.DEFAULT_RDF_NAMESPACES = {
  183.   "http://www.w3.org/1999/02/22-rdf-syntax-ns#": "",
  184.   "http://www.mozilla.org/2004/em-rdf#": "",
  185.   "http://www.songbirdnest.com/2007/addon-metadata-rdf#": ""
  186. };
  187.  
  188. RDFHelper.DEFAULT_RDF_NAMESPACES_PREFIXED = {
  189.   "http://www.w3.org/1999/02/22-rdf-syntax-ns#": "rdf_",
  190.   "http://www.mozilla.org/2004/em-rdf#": "moz_",
  191.   "http://www.songbirdnest.com/2007/addon-metadata-rdf#": "sb_"
  192. };
  193.