rdflib 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- module.exports = $rdf = function() {
1
+ (function(root, undef) {
2
2
  /**
3
3
  * Utility functions for $rdf and the $rdf object itself
4
4
  */
@@ -482,17 +482,6 @@ $rdf.uri = (function() {
482
482
  return base.slice(0, baseSingle) + path;
483
483
  };
484
484
 
485
- uri.join2 = function(given, base) {
486
- var baseURI, tIOService;
487
- if (typeof tabulator !== "undefined" && tabulator !== null ? tabulator.isExtension : void 0) {
488
- tIOService = Components.classes['@mozilla.org/network/io-service;1'].getService(Components.interfaces.nsIIOService);
489
- baseURI = tIOService.newURI(base, null, null);
490
- return tIOService.newURI(baseURI.resolve(given), null, null).spec;
491
- } else {
492
- return this.join(given, base);
493
- }
494
- };
495
-
496
485
  uri.commonHost = new RegExp('^[-_a-zA-Z0-9.]+:(//[^/]*)?/[^/]*$');
497
486
 
498
487
  uri.hostpart = function(u) {
@@ -653,8 +642,10 @@ $rdf.Empty = (function() {
653
642
  })();
654
643
 
655
644
  /*
656
- an RDF URI
657
- todo: badly named.
645
+ A named node in an RDF graph
646
+ todo: badly named.
647
+ No, formally a URI is a string, this is a node whose name is a URI.
648
+ Connolly pointed out it isa symbol on the language.
658
649
  @param uri the uri as string
659
650
  */
660
651
 
@@ -1446,10 +1437,9 @@ if ((typeof module !== "undefined" && module !== null ? module.exports : void 0)
1446
1437
  module.exports[k] = v;
1447
1438
  }
1448
1439
  }
1449
- /* vim: set ts=2 sts=2 sw=2 et: */
1450
1440
  /**
1451
1441
  * @fileoverview
1452
- * TABULATOR RDF PARSER
1442
+ * RDF/XML PARSER
1453
1443
  *
1454
1444
  * Version 0.1
1455
1445
  * Parser believed to be in full positive RDF/XML parsing compliance
@@ -1458,7 +1448,6 @@ if ((typeof module !== "undefined" && module !== null ? module.exports : void 0)
1458
1448
  * and industry standards where appropriate (DOM, ECMAScript, &c.)
1459
1449
  *
1460
1450
  * Author: David Sheets <dsheets@mit.edu>
1461
- * SVN ID: $Id$
1462
1451
  *
1463
1452
  * W3C® SOFTWARE NOTICE AND LICENSE
1464
1453
  * http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
@@ -1467,13 +1456,13 @@ if ((typeof module !== "undefined" && module !== null ? module.exports : void 0)
1467
1456
  * the following license. By obtaining, using and/or copying this work,
1468
1457
  * you (the licensee) agree that you have read, understood, and will
1469
1458
  * comply with the following terms and conditions.
1470
- *
1459
+ *
1471
1460
  * Permission to copy, modify, and distribute this software and its
1472
1461
  * documentation, with or without modification, for any purpose and
1473
1462
  * without fee or royalty is hereby granted, provided that you include
1474
1463
  * the following on ALL copies of the software and documentation or
1475
1464
  * portions thereof, including modifications:
1476
- *
1465
+ *
1477
1466
  * 1. The full text of this NOTICE in a location viewable to users of
1478
1467
  * the redistributed or derivative work.
1479
1468
  * 2. Any pre-existing intellectual property disclaimers, notices, or terms and
@@ -1483,18 +1472,18 @@ if ((typeof module !== "undefined" && module !== null ? module.exports : void 0)
1483
1472
  * 3. Notice of any changes or modifications to the files, including the
1484
1473
  * date changes were made. (We recommend you provide URIs to the location
1485
1474
  * from which the code is derived.)
1486
- *
1475
+ *
1487
1476
  * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT
1488
1477
  * HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED,
1489
1478
  * INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS
1490
1479
  * FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR
1491
1480
  * DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS,
1492
1481
  * TRADEMARKS OR OTHER RIGHTS.
1493
- *
1482
+ *
1494
1483
  * COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL
1495
1484
  * OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR
1496
1485
  * DOCUMENTATION.
1497
- *
1486
+ *
1498
1487
  * The name and trademarks of copyright holders may NOT be used in
1499
1488
  * advertising or publicity pertaining to the software without specific,
1500
1489
  * written prior permission. Title to copyright in this software and any
@@ -1503,567 +1492,436 @@ if ((typeof module !== "undefined" && module !== null ? module.exports : void 0)
1503
1492
  */
1504
1493
  /**
1505
1494
  * @class Class defining an RDFParser resource object tied to an RDFStore
1506
- *
1495
+ *
1507
1496
  * @author David Sheets <dsheets@mit.edu>
1508
1497
  * @version 0.1
1509
- *
1498
+ *
1510
1499
  * @constructor
1511
1500
  * @param {RDFStore} store An RDFStore object
1512
1501
  */
1513
- $rdf.RDFParser = function (store) {
1514
- var RDFParser = {};
1515
-
1516
- /** Standard namespaces that we know how to handle @final
1517
- * @member RDFParser
1518
- */
1519
- RDFParser['ns'] = {
1520
- 'RDF': "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
1521
- 'RDFS': "http://www.w3.org/2000/01/rdf-schema#"
1522
- };
1523
- /** DOM Level 2 node type magic numbers @final
1524
- * @member RDFParser
1525
- */
1526
- RDFParser['nodeType'] = {
1527
- 'ELEMENT': 1, 'ATTRIBUTE': 2, 'TEXT': 3,
1528
- 'CDATA_SECTION': 4, 'ENTITY_REFERENCE': 5,
1529
- 'ENTITY': 6, 'PROCESSING_INSTRUCTION': 7,
1530
- 'COMMENT': 8, 'DOCUMENT': 9, 'DOCUMENT_TYPE': 10,
1531
- 'DOCUMENT_FRAGMENT': 11, 'NOTATION': 12
1532
- };
1502
+
1503
+ $rdf.RDFParser = function(store){
1504
+ var RDFParser = {};
1505
+
1506
+ /** Standard namespaces that we know how to handle @final
1507
+ * @member RDFParser
1508
+ */
1509
+ RDFParser.ns = {'RDF': "http://www.w3.org/1999/02/22-rdf-syntax-ns#", 'RDFS': "http://www.w3.org/2000/01/rdf-schema#"};
1510
+
1511
+ /** DOM Level 2 node type magic numbers @final
1512
+ * @member RDFParser
1513
+ */
1514
+ RDFParser.nodeType = {'ELEMENT': 1, 'ATTRIBUTE': 2, 'TEXT': 3,
1515
+ 'CDATA_SECTION': 4, 'ENTITY_REFERENCE': 5,
1516
+ 'ENTITY': 6, 'PROCESSING_INSTRUCTION': 7,
1517
+ 'COMMENT': 8, 'DOCUMENT': 9, 'DOCUMENT_TYPE': 10,
1518
+ 'DOCUMENT_FRAGMENT': 11, 'NOTATION': 12};
1533
1519
 
1534
- /**
1535
- * Frame class for namespace and base URI lookups
1536
- * Base lookups will always resolve because the parser knows
1537
- * the default base.
1538
- *
1539
- * @private
1540
- */
1541
- this['frameFactory'] = function (parser, parent, element) {
1542
- return {
1543
- 'NODE': 1,
1544
- 'ARC': 2,
1545
- 'parent': parent,
1546
- 'parser': parser,
1547
- 'store': parser['store'],
1548
- 'element': element,
1549
- 'lastChild': 0,
1550
- 'base': null,
1551
- 'lang': null,
1552
- 'node': null,
1553
- 'nodeType': null,
1554
- 'listIndex': 1,
1555
- 'rdfid': null,
1556
- 'datatype': null,
1557
- 'collection': false,
1558
-
1559
- /** Terminate the frame and notify the store that we're done */
1560
- 'terminateFrame': function () {
1561
- if (this['collection']) {
1562
- this['node']['close']();
1563
- }
1564
- },
1565
-
1566
- /** Add a symbol of a certain type to the this frame */
1567
- 'addSymbol': function (type, uri) {
1568
- uri = $rdf.Util.uri.join(uri, this['base']);
1569
- this['node'] = this['store']['sym'](uri);
1570
- this['nodeType'] = type;
1571
- },
1572
-
1573
- /** Load any constructed triples into the store */
1574
- 'loadTriple': function () {
1575
- if (this['parent']['parent']['collection']) {
1576
- this['parent']['parent']['node']['append'](this['node']);
1520
+ /**
1521
+ * Frame class for namespace and base URI lookups
1522
+ * Base lookups will always resolve because the parser knows
1523
+ * the default base.
1524
+ *
1525
+ * @private
1526
+ */
1527
+
1528
+ this.frameFactory = function(parser, parent, element){
1529
+ return {'NODE': 1, 'ARC': 2, 'parent': parent, 'parser': parser, 'store': parser.store, 'element': element,
1530
+ 'lastChild': 0, 'base': null, 'lang': null, 'node': null, 'nodeType': null, 'listIndex': 1, 'rdfid': null, 'datatype': null, 'collection': false, /** Terminate the frame and notify the store that we're done */
1531
+ 'terminateFrame': function(){
1532
+ if (this.collection){
1533
+
1534
+ this.node.close();
1535
+ }
1577
1536
  }
1578
- else {
1579
- this['store']['add'](
1580
- this['parent']['parent']['node'],
1581
- this['parent']['node'],
1582
- this['node'],
1583
- this['parser']['why']
1584
- );
1585
- }
1586
- if (this['parent']['rdfid']) { // reify
1587
- var triple = this['store']['sym'](
1588
- $rdf.Util.uri.join("#"+this['parent']['rdfid'],
1589
- this['base'])
1590
- );
1591
- this['store']['add'](triple,
1592
- this['store']['sym'](
1593
- RDFParser['ns']['RDF'] + "type"
1594
- ),
1595
- this['store']['sym'](
1596
- RDFParser['ns']['RDF'] + "Statement"
1597
- ),
1598
- this['parser']['why']
1599
- );
1600
- this['store']['add'](triple,
1601
- this['store']['sym'](
1602
- RDFParser['ns']['RDF'] + "subject"
1603
- ),
1604
- this['parent']['parent']['node'],
1605
- this['parser']['why']
1606
- );
1607
- this['store']['add'](triple,
1608
- this['store']['sym'](
1609
- RDFParser['ns']['RDF'] + "predicate"
1610
- ),
1611
- this['parent']['node'],
1612
- this['parser']['why']
1613
- );
1614
- this['store']['add'](triple,
1615
- this['store']['sym'](
1616
- RDFParser['ns']['RDF'] + "object"),
1617
- this['node'],
1618
- this['parser']['why']
1619
- );
1620
- }
1621
- },
1622
-
1623
- /** Check if it's OK to load a triple */
1624
- 'isTripleToLoad': function () {
1625
- return ((this['parent']) &&
1626
- (this['parent']['parent']) &&
1627
- (this['nodeType'] === this['NODE']) &&
1628
- (this['parent']['nodeType'] === this['ARC']) &&
1629
- (this['parent']['parent']['nodeType'] === this['NODE']));
1630
- },
1631
-
1632
- /** Add a symbolic node to this frame */
1633
- 'addNode': function (uri) {
1634
- this['addSymbol'](this['NODE'],uri);
1635
- if (this['isTripleToLoad']()) {
1636
- this['loadTriple']();
1637
- }
1638
- },
1639
-
1640
- /** Add a collection node to this frame */
1641
- 'addCollection': function () {
1642
- this['nodeType'] = this['NODE'];
1643
- this['node'] = this['store']['collection']();
1644
- this['collection'] = true;
1645
- if (this['isTripleToLoad']()) {
1646
- this['loadTriple']();
1647
- }
1648
- },
1649
-
1650
- /** Add a collection arc to this frame */
1651
- 'addCollectionArc': function () {
1652
- this['nodeType'] = this['ARC'];
1653
- },
1654
-
1655
- /** Add a bnode to this frame */
1656
- 'addBNode': function (id) {
1657
- if (id) {
1658
- if (this['parser']['bnodes'][id]) {
1659
- this['node'] = this['parser']['bnodes'][id];
1660
- } else {
1661
- this['node'] = this['parser']['bnodes'][id] = this['store']['bnode']();
1662
- }
1663
- } else {
1664
- this['node'] = this['store']['bnode']();
1537
+ , /** Add a symbol of a certain type to the this frame */'addSymbol': function(type, uri){
1538
+ uri = $rdf.Util.uri.join(uri, this.base);
1539
+ this.node = this.store.sym(uri);
1540
+
1541
+ this.nodeType = type;
1665
1542
  }
1666
-
1667
- this['nodeType'] = this['NODE'];
1668
- if (this['isTripleToLoad']()) {
1669
- this['loadTriple']();
1543
+ , /** Load any constructed triples into the store */'loadTriple': function(){
1544
+ if (this.parent.parent.collection){
1545
+ this.parent.parent.node.append(this.node);
1546
+ }
1547
+ else {
1548
+ this.store.add(this.parent.parent.node, this.parent.node, this.node, this.parser.why);
1549
+ }
1550
+ if (this.parent.rdfid != null){
1551
+ // reify
1552
+ var triple = this.store.sym($rdf.Util.uri.join("#" + this.parent.rdfid, this.base));
1553
+ this.store.add(triple, this.store.sym(RDFParser.ns.RDF + "type"), this.store.sym(RDFParser.ns.RDF + "Statement"), this.parser.why);
1554
+ this.store.add(triple, this.store.sym(RDFParser.ns.RDF + "subject"), this.parent.parent.node, this.parser.why);
1555
+ this.store.add(triple, this.store.sym(RDFParser.ns.RDF + "predicate"), this.parent.node, this.parser.why);
1556
+
1557
+ this.store.add(triple, this.store.sym(RDFParser.ns.RDF + "object"), this.node, this.parser.why);
1558
+ }
1670
1559
  }
1671
- },
1672
-
1673
- /** Add an arc or property to this frame */
1674
- 'addArc': function (uri) {
1675
- if (uri === RDFParser['ns']['RDF']+"li") {
1676
- uri = RDFParser['ns']['RDF'] + "_" + this['parent']['listIndex']++;
1560
+ , /** Check if it's OK to load a triple */'isTripleToLoad': function(){
1561
+
1562
+ return (this.parent != null && this.parent.parent != null && this.nodeType === this.NODE && this.parent.nodeType ===
1563
+ this.ARC && this.parent.parent.nodeType === this.NODE);
1677
1564
  }
1678
- this['addSymbol'](this['ARC'], uri);
1679
- },
1680
-
1681
- /** Add a literal to this frame */
1682
- 'addLiteral': function (value) {
1683
- if (this['parent']['datatype']) {
1684
- this['node'] = this['store']['literal'](
1685
- value, "",
1686
- this['store']['sym'](this['parent']['datatype'])
1687
- );
1688
- } else {
1689
- this['node'] = this['store']['literal'](value, this['lang']);
1565
+ , /** Add a symbolic node to this frame */'addNode': function(uri){
1566
+ this.addSymbol(this.NODE, uri);
1567
+ if (this.isTripleToLoad()){
1568
+
1569
+ this.loadTriple();
1570
+ }
1690
1571
  }
1691
- this['nodeType'] = this['NODE'];
1692
- if (this['isTripleToLoad']()) {
1693
- this['loadTriple']();
1572
+ , /** Add a collection node to this frame */'addCollection': function(){
1573
+ this.nodeType = this.NODE;
1574
+ this.node = this.store.collection();
1575
+ this.collection = true;
1576
+ if (this.isTripleToLoad()){
1577
+
1578
+ this.loadTriple();
1579
+ }
1694
1580
  }
1695
- }
1696
- };
1697
- };
1698
-
1699
- // from the OpenLayers source .. needed to get around IE problems.
1700
- this['getAttributeNodeNS'] = function(node, uri, name) {
1701
- var attributeNode = null;
1702
- if(node.getAttributeNodeNS) {
1703
- attributeNode = node.getAttributeNodeNS(uri, name);
1704
- } else {
1705
- var attributes = node.attributes;
1706
- var potentialNode, fullName;
1707
- for (var i = 0, len = attributes.length; i < len; i = i + i) {
1708
- potentialNode = attributes[i];
1709
- if (potentialNode.namespaceURI === uri) {
1710
- fullName = (potentialNode.prefix) ?
1711
- (potentialNode.prefix + ":" + name) : name;
1712
- if (fullName === potentialNode.nodeName) {
1713
- attributeNode = potentialNode;
1714
- break;
1715
- }
1581
+ , /** Add a collection arc to this frame */'addCollectionArc': function(){
1582
+
1583
+ this.nodeType = this.ARC;
1716
1584
  }
1717
- }
1718
- }
1719
- return attributeNode;
1720
- };
1721
-
1722
- /** Our triple store reference @private */
1723
- this['store'] = store;
1724
- /** Our identified blank nodes @private */
1725
- this['bnodes'] = {};
1726
- /** A context for context-aware stores @private */
1727
- this['why'] = null;
1728
- /** Reification flag */
1729
- this['reify'] = false;
1730
-
1731
- /**
1732
- * Build our initial scope frame and parse the DOM into triples
1733
- * @param {DOMTree} document The DOM to parse
1734
- * @param {String} base The base URL to use
1735
- * @param {Object} why The context to which this resource belongs
1736
- */
1737
- this['parse'] = function (document, base, why) {
1738
- var children = document['childNodes'];
1739
-
1740
- // clean up for the next run
1741
- this['cleanParser']();
1742
-
1743
- var root;
1744
- // figure out the root element
1745
- //var root = document.documentElement; //this is faster, I think, cross-browser issue? well, DOM 2
1746
- if (document['nodeType'] === RDFParser['nodeType']['DOCUMENT']) {
1747
- for (var c = 0, len = children['length']; c < len; c = c + 1) {
1748
- if (children[c]['nodeType'] === RDFParser['nodeType']['ELEMENT']) {
1749
- root = children[c];
1750
- break;
1585
+ , /** Add a bnode to this frame */'addBNode': function(id){
1586
+ if (id != null){
1587
+ if (this.parser.bnodes[id] != null){
1588
+ this.node = this.parser.bnodes[id];
1589
+ }
1590
+ else {
1591
+ this.node = this.parser.bnodes[id] = this.store.bnode();
1592
+ }
1593
+ }
1594
+ else {
1595
+ this.node = this.store.bnode();
1596
+ }
1597
+ this.nodeType = this.NODE;
1598
+ if (this.isTripleToLoad()){
1599
+
1600
+ this.loadTriple();
1601
+ }
1751
1602
  }
1752
- }
1753
- }
1754
- else if (document['nodeType'] === RDFParser['nodeType']['ELEMENT']) {
1755
- root = document;
1756
- }
1757
- else {
1758
- throw new Error("RDFParser: can't find root in " + base + ". Halting. ");
1759
- }
1760
-
1761
- this['why'] = why;
1762
-
1763
- // our topmost frame
1764
- var f = this['frameFactory'](this);
1765
- this['base'] = base;
1766
- f['base'] = base;
1767
- f['lang'] = '';
1768
-
1769
- this['parseDOM'](this['buildFrame'](f,root));
1770
- return true;
1771
- };
1772
-
1773
- this['parseDOM'] = function (frame) {
1774
- // a DOM utility function used in parsing
1775
- var elementURI = function (el) {
1776
- var result = "";
1777
- if (!el['namespaceURI']) {
1778
- throw new Error("RDF/XML syntax error: No namespace for " +
1779
- el['localName'] + " in " + this.base);
1780
- } else if( el['localName'] ) {
1781
- result = result + el['localName'];
1782
- } else if( el['nodeName'] ) {
1783
- if (el['nodeName'].indexOf(":") >= 0) {
1784
- result = result + el['nodeName'].split(":")[1];
1785
- } else {
1786
- result = result + el['nodeName'];
1603
+ , /** Add an arc or property to this frame */'addArc': function(uri){
1604
+ if (uri === RDFParser.ns.RDF + "li"){
1605
+ uri = RDFParser.ns.RDF + "_" + this.parent.listIndex;
1606
+ this.parent.listIndex++;
1607
+ }
1608
+
1609
+ this.addSymbol(this.ARC, uri);
1787
1610
  }
1788
- } else {
1789
- result = result + el['namespaceURI'];
1790
- }
1791
- return result;
1792
- }.bind(this);
1793
-
1794
- var dig = true; // if we'll dig down in the tree on the next iter
1795
-
1796
- while (frame['parent']) {
1797
- var dom = frame['element'];
1798
- var attrs = dom['attributes'];
1799
- var rdfid, bnid;
1800
-
1801
- if ((dom['nodeType'] === RDFParser['nodeType']['TEXT']) ||
1802
- (dom['nodeType'] === RDFParser['nodeType']['CDATA_SECTION'])) {//we have a literal
1803
- frame['addLiteral'](dom['nodeValue']);
1804
- } else if (elementURI(dom) !== RDFParser['ns']['RDF'] + "RDF") { // not root
1805
- if (frame['parent'] && frame['parent']['collection']) {
1806
- // we're a collection element
1807
- frame['addCollectionArc']();
1808
- frame = this['buildFrame'](frame,frame['element']);
1809
- frame['parent']['element'] = null;
1810
- }
1811
-
1812
- if ((!frame['parent']) ||
1813
- (!frame['parent']['nodeType']) ||
1814
- (frame['parent']['nodeType'] === frame['ARC'])) {
1815
- // we need a node
1816
- var about = this['getAttributeNodeNS'](dom,
1817
- RDFParser['ns']['RDF'],
1818
- "about"
1819
- );
1820
- rdfid = this['getAttributeNodeNS'](dom,
1821
- RDFParser['ns']['RDF'],
1822
- "ID"
1823
- );
1824
- if (about && rdfid) {
1825
- throw new Error("RDFParser: " + dom['nodeName'] +
1826
- " has both rdf:id and rdf:about." +
1827
- " Halting. Only one of these" +
1828
- " properties may be specified on a" +
1829
- " node.");
1830
- }
1831
-
1832
- if ((!about) && (rdfid)) {
1833
- frame['addNode']("#" + rdfid['nodeValue']);
1834
- dom['removeAttributeNode'](rdfid);
1835
- } else if ((!about) && (!rdfid)) {
1836
- bnid = this['getAttributeNodeNS'](dom,
1837
- RDFParser['ns']['RDF'],
1838
- "nodeID"
1839
- );
1840
- if (bnid) {
1841
- frame['addBNode'](bnid['nodeValue']);
1842
- dom['removeAttributeNode'](bnid);
1843
- } else {
1844
- frame['addBNode']();
1611
+ , /** Add a literal to this frame */'addLiteral': function(value){
1612
+ if (this.parent.datatype){
1613
+ this.node = this.store.literal(value, "", this.store.sym(this.parent.datatype));
1845
1614
  }
1846
- } else {
1847
- frame['addNode'](about['nodeValue']);
1848
- dom['removeAttributeNode'](about);
1849
- }
1850
-
1851
- // Typed nodes
1852
- var rdftype = this['getAttributeNodeNS'](dom,
1853
- RDFParser['ns']['RDF'],
1854
- "type"
1855
- );
1856
- if (RDFParser['ns']['RDF'] + "Description" !== elementURI(dom)) {
1857
- rdftype = {'nodeValue': elementURI(dom)};
1858
- }
1859
-
1860
- if (rdftype) {
1861
- this['store']['add'](
1862
- frame['node'],
1863
- this['store']['sym'](
1864
- RDFParser['ns']['RDF'] + "type"
1865
- ),
1866
- this['store']['sym'](
1867
- $rdf.Util.uri.join(
1868
- rdftype['nodeValue'],
1869
- frame['base']
1870
- )
1871
- ),
1872
- this['why']
1873
- );
1874
- if (rdftype['nodeName']) {
1875
- dom['removeAttributeNode'](rdftype);
1615
+ else {
1616
+ this.node = this.store.literal(value, this.lang);
1876
1617
  }
1877
- }
1878
-
1879
- // Property Attributes
1880
- for (var x = attrs['length']-1; x >= 0; x--) {
1881
- this['store']['add'](
1882
- frame['node'],
1883
- this['store']['sym'](elementURI(attrs[x])),
1884
- this['store']['literal'](
1885
- attrs[x]['nodeValue'],
1886
- frame['lang']
1887
- ),
1888
- this['why']
1889
- );
1890
- }
1891
- } else { // we should add an arc (or implicit bnode+arc)
1892
- frame['addArc'](elementURI(dom));
1893
-
1894
- // save the arc's rdf:ID if it has one
1895
- if (this['reify']) {
1896
- rdfid = this['getAttributeNodeNS'](dom,
1897
- RDFParser['ns']['RDF'],
1898
- "ID"
1899
- );
1900
- if (rdfid) {
1901
- frame['rdfid'] = rdfid['nodeValue'];
1902
- dom['removeAttributeNode'](rdfid);
1618
+ this.nodeType = this.NODE;
1619
+ if (this.isTripleToLoad()){
1620
+ this.loadTriple();
1903
1621
  }
1904
- }
1905
-
1906
- var parsetype = this['getAttributeNodeNS'](dom,
1907
- RDFParser['ns']['RDF'],
1908
- "parseType"
1909
- );
1910
- var datatype = this['getAttributeNodeNS'](dom,
1911
- RDFParser['ns']['RDF'],
1912
- "datatype"
1913
- );
1914
- if (datatype) {
1915
- frame['datatype'] = datatype['nodeValue'];
1916
- dom['removeAttributeNode'](datatype);
1917
- }
1918
-
1919
- if (parsetype) {
1920
- var nv = parsetype['nodeValue'];
1921
- if (nv === "Literal") {
1922
- frame['datatype'] = RDFParser['ns']['RDF'] + "XMLLiteral";
1923
- // (this.buildFrame(frame)).addLiteral(dom)
1924
- // should work but doesn't
1925
- frame = this['buildFrame'](frame);
1926
- frame['addLiteral'](dom);
1927
- dig = false;
1928
- } else if (nv === "Resource") {
1929
- frame = this['buildFrame'](frame,frame['element']);
1930
- frame['parent']['element'] = null;
1931
- frame['addBNode']();
1932
- } else if (nv == "Collection") {
1933
- frame = this['buildFrame'](frame,frame['element']);
1934
- frame['parent']['element'] = null;
1935
- frame['addCollection']();
1936
- }
1937
- dom['removeAttributeNode'](parsetype);
1938
- }
1939
-
1940
- if (attrs['length'] !== 0) {
1941
- var resource = this['getAttributeNodeNS'](dom,
1942
- RDFParser['ns']['RDF'],
1943
- "resource"
1944
- );
1945
- bnid = this['getAttributeNodeNS'](dom,
1946
- RDFParser['ns']['RDF'],
1947
- "nodeID"
1948
- );
1949
-
1950
- frame = this['buildFrame'](frame);
1951
- if (resource) {
1952
- frame['addNode'](resource['nodeValue']);
1953
- dom['removeAttributeNode'](resource);
1954
- } else {
1955
- if (bnid) {
1956
- frame['addBNode'](bnid['nodeValue']);
1957
- dom['removeAttributeNode'](bnid);
1958
- } else {
1959
- frame['addBNode']();
1960
- }
1961
- }
1962
-
1963
- for (var y = attrs['length']-1; y >= 0; y--) {
1964
- var f = this['buildFrame'](frame);
1965
- f['addArc'](elementURI(attrs[y]));
1966
- if (elementURI(attrs[y]) === RDFParser['ns']['RDF'] + "type") {
1967
- (this['buildFrame'](f))['addNode'](attrs[y]['nodeValue']);
1968
- } else {
1969
- (this['buildFrame'](f))['addLiteral'](attrs[y]['nodeValue']);
1970
- }
1971
- }
1972
- } else if (dom['childNodes']['length'] === 0) {
1973
- (this['buildFrame'](frame))['addLiteral']("");
1974
- }
1975
1622
  }
1976
- } // rdf:RDF
1977
-
1978
- // dig dug
1979
- dom = frame['element'];
1980
- while (frame['parent']) {
1981
- var pframe = frame;
1982
- while (!dom) {
1983
- frame = frame['parent'];
1984
- dom = frame['element'];
1985
- }
1986
- var candidate = dom['childNodes'][frame['lastChild']];
1987
- if ((!candidate) || (!dig)) {
1988
- frame['terminateFrame']();
1989
- if (!(frame = frame['parent'])) { break; } // done
1990
- dom = frame['element'];
1991
- dig = true;
1992
- } else if (((candidate['nodeType'] !== RDFParser['nodeType']['ELEMENT']) &&
1993
- (candidate['nodeType'] !== RDFParser['nodeType']['TEXT']) &&
1994
- (candidate['nodeType'] !== RDFParser['nodeType']['CDATA_SECTION'])) ||
1995
- ((candidate['nodeType'] === RDFParser['nodeType']['TEXT']) ||
1996
- (candidate['nodeType'] === RDFParser['nodeType']['CDATA_SECTION'])) &&
1997
- (dom['childNodes']['length'] != 1)) {
1998
- frame['lastChild']++;
1999
- } else { // not a leaf
2000
- frame['lastChild']++;
2001
- frame = this['buildFrame'](
2002
- pframe,
2003
- dom['childNodes'][frame['lastChild'] - 1]
2004
- );
2005
- break;
1623
+ };
1624
+ };
1625
+
1626
+ //from the OpenLayers source .. needed to get around IE problems.
1627
+ this.getAttributeNodeNS = function(node, uri, name){
1628
+ var attributeNode = null;
1629
+ if (node.getAttributeNodeNS){
1630
+ attributeNode = node.getAttributeNodeNS(uri, name);
2006
1631
  }
2007
- } // while
2008
- } // while
2009
-
1632
+ else {
1633
+ var attributes = node.attributes;
1634
+ var potentialNode, fullName;
1635
+ for (var i = 0;i < attributes.length; ++ i){
1636
+ potentialNode = attributes[i];
1637
+ if (potentialNode.namespaceURI === uri){
1638
+ fullName = (potentialNode.prefix) ? (potentialNode.prefix +":" + name): name;
1639
+ if (fullName === potentialNode.nodeName){
1640
+ attributeNode = potentialNode;
1641
+ break;
1642
+ }
1643
+ }
1644
+ }
1645
+ }
1646
+ return attributeNode;
1647
+ };
1648
+
1649
+
1650
+ /** Our triple store reference @private */
1651
+
1652
+ this.store = store;/** Our identified blank nodes @private */
1653
+ this.bnodes = {};/** A context for context-aware stores @private */
1654
+ this.why = null;/** Reification flag */
1655
+ this.reify = false;
1656
+
1657
+ /**
1658
+ * Build our initial scope frame and parse the DOM into triples
1659
+ * @param {DOMTree} document The DOM to parse
1660
+ * @param {String} base The base URL to use
1661
+ * @param {Object} why The context to which this resource belongs
1662
+ */
1663
+
1664
+ this.parse = function(document, base, why){
1665
+ var children = document.childNodes;// clean up for the next run
1666
+ this.cleanParser();// figure out the root element
1667
+ var root;
1668
+ if (document.nodeType === RDFParser.nodeType.DOCUMENT){
1669
+ for (var c = 0;c < children.length;c++){
1670
+ if (children[c].nodeType === RDFParser.nodeType.ELEMENT){
1671
+ root = children[c];
1672
+ break;
1673
+ }
1674
+ }
1675
+ }
1676
+ else if (document.nodeType === RDFParser.nodeType.ELEMENT){
1677
+ root = document;
1678
+ }
1679
+ else {
1680
+ throw new Error("RDFParser: can't find root in " + base +". Halting. ");
1681
+ // return false;
1682
+ }
1683
+ this.why = why;// our topmost frame
1684
+ var f = this.frameFactory(this);
1685
+ this.base = base;
1686
+ f.base = base;
1687
+ f.lang = '';
1688
+ this.parseDOM(this.buildFrame(f, root));
1689
+ return true;
1690
+ };
1691
+
1692
+ this.parseDOM = function(frame){
1693
+ // a DOM utility function used in parsing
1694
+ var rdfid;
1695
+ var elementURI = function(el){
1696
+ var result = "";
1697
+ if (el.namespaceURI == null){
1698
+ throw new Error("RDF/XML syntax error: No namespace for " + el.localName + " in " + this.base);
1699
+ }
1700
+ if (el.namespaceURI){
1701
+ result = result + el.namespaceURI;
1702
+ }
1703
+ if (el.localName){
1704
+ result = result + el.localName;
1705
+ }
1706
+ else if (el.nodeName){
1707
+ if (el.nodeName.indexOf(":") >= 0)result = result + el.nodeName.split(":")[1];
1708
+ else result = result + el.nodeName;
1709
+ }
1710
+ return result;
1711
+ }.bind(this);
1712
+ var dig = true;// if we'll dig down in the tree on the next iter
1713
+ while (frame.parent){
1714
+ var dom = frame.element;
1715
+ var attrs = dom.attributes;
1716
+ if (dom.nodeType === RDFParser.nodeType.TEXT || dom.nodeType === RDFParser.nodeType.CDATA_SECTION){
1717
+ //we have a literal
1718
+ frame.addLiteral(dom.nodeValue);
1719
+ }
1720
+ else if (elementURI(dom)!== RDFParser.ns.RDF + "RDF"){
1721
+ // not root
1722
+ if (frame.parent && frame.parent.collection){
1723
+ // we're a collection element
1724
+ frame.addCollectionArc();
1725
+ frame = this.buildFrame(frame, frame.element);
1726
+ frame.parent.element = null;
1727
+ }
1728
+ if ( ! frame.parent || ! frame.parent.nodeType || frame.parent.nodeType === frame.ARC){
1729
+ // we need a node
1730
+ var about = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "about");
1731
+ rdfid = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "ID");
1732
+ if (about && rdfid){
1733
+ throw new Error("RDFParser: " + dom.nodeName + " has both rdf:id and rdf:about." +
1734
+ " Halting. Only one of these" + " properties may be specified on a" + " node.");
1735
+ }
1736
+ if (!about && rdfid){
1737
+ frame.addNode("#" + rdfid.nodeValue);
1738
+ dom.removeAttributeNode(rdfid);
1739
+ }
1740
+ else if (about == null && rdfid == null){
1741
+ var bnid = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "nodeID");
1742
+ if (bnid){
1743
+ frame.addBNode(bnid.nodeValue);
1744
+ dom.removeAttributeNode(bnid);
1745
+ }
1746
+ else {
1747
+ frame.addBNode();
1748
+ }
1749
+ }
1750
+ else {
1751
+ frame.addNode(about.nodeValue);
1752
+ dom.removeAttributeNode(about);
1753
+ }
1754
+ // Typed nodes
1755
+ var rdftype = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "type");
1756
+ if (RDFParser.ns.RDF + "Description" !== elementURI(dom)){
1757
+ rdftype = {'nodeValue': elementURI(dom)};
1758
+ }
1759
+ if (rdftype != null){
1760
+ this.store.add(frame.node, this.store.sym(RDFParser.ns.RDF + "type"), this.store.sym($rdf.Util.uri.join(rdftype.nodeValue,
1761
+ frame.base)), this.why);
1762
+ if (rdftype.nodeName){
1763
+ dom.removeAttributeNode(rdftype);
1764
+ }
1765
+ }
1766
+ // Property Attributes
1767
+ for (var x = attrs.length - 1;x >= 0;x--){
1768
+ this.store.add(frame.node, this.store.sym(elementURI(attrs[x])), this.store.literal(attrs[x].nodeValue,
1769
+ frame.lang), this.why);
1770
+ }
1771
+ }
1772
+ else {
1773
+ // we should add an arc (or implicit bnode+arc)
1774
+ frame.addArc(elementURI(dom));// save the arc's rdf:ID if it has one
1775
+ if (this.reify){
1776
+ rdfid = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "ID");
1777
+ if (rdfid){
1778
+ frame.rdfid = rdfid.nodeValue;
1779
+ dom.removeAttributeNode(rdfid);
1780
+ }
1781
+ }
1782
+ var parsetype = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "parseType");
1783
+ var datatype = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "datatype");
1784
+ if (datatype){
1785
+ frame.datatype = datatype.nodeValue;
1786
+ dom.removeAttributeNode(datatype);
1787
+ }
1788
+ if (parsetype){
1789
+ var nv = parsetype.nodeValue;
1790
+ if (nv === "Literal"){
1791
+ frame.datatype = RDFParser.ns.RDF + "XMLLiteral";// (this.buildFrame(frame)).addLiteral(dom)
1792
+ // should work but doesn't
1793
+ frame = this.buildFrame(frame);
1794
+ frame.addLiteral(dom);
1795
+ dig = false;
1796
+ }
1797
+ else if (nv === "Resource"){
1798
+ frame = this.buildFrame(frame, frame.element);
1799
+ frame.parent.element = null;
1800
+ frame.addBNode();
1801
+ }
1802
+ else if (nv === "Collection"){
1803
+ frame = this.buildFrame(frame, frame.element);
1804
+ frame.parent.element = null;
1805
+ frame.addCollection();
1806
+ }
1807
+ dom.removeAttributeNode(parsetype);
1808
+ }
1809
+ if (attrs.length !== 0){
1810
+ var resource = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "resource");
1811
+ var bnid2 = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, "nodeID");
1812
+ frame = this.buildFrame(frame);
1813
+ if (resource){
1814
+ frame.addNode(resource.nodeValue);
1815
+ dom.removeAttributeNode(resource);
1816
+ }
1817
+ else {
1818
+ if (bnid2){
1819
+ frame.addBNode(bnid2.nodeValue);
1820
+ dom.removeAttributeNode(bnid2);
1821
+ }
1822
+ else {
1823
+ frame.addBNode();
1824
+ }
1825
+ }
1826
+ for (var x1 = attrs.length - 1; x1 >= 0; x1--){
1827
+ var f = this.buildFrame(frame);
1828
+ f.addArc(elementURI(attrs[x1]));
1829
+ if (elementURI(attrs[x1])=== RDFParser.ns.RDF + "type"){
1830
+ (this.buildFrame(f)).addNode(attrs[x1].nodeValue);
1831
+ }
1832
+ else {
1833
+ (this.buildFrame(f)).addLiteral(attrs[x1].nodeValue);
1834
+ }
1835
+ }
1836
+ }
1837
+ else if (dom.childNodes.length === 0){
1838
+ (this.buildFrame(frame)).addLiteral("");
1839
+ }
1840
+ }
1841
+ }// rdf:RDF
1842
+ // dig dug
1843
+ dom = frame.element;
1844
+ while (frame.parent){
1845
+ var pframe = frame;
1846
+ while (dom == null){
1847
+ frame = frame.parent;
1848
+ dom = frame.element;
1849
+ }
1850
+ var candidate = dom.childNodes && dom.childNodes[frame.lastChild];
1851
+ if (!candidate || ! dig){
1852
+ frame.terminateFrame();
1853
+ if ( ! (frame = frame.parent)){
1854
+ break;
1855
+ }// done
1856
+ dom = frame.element;
1857
+ dig = true;
1858
+ }
1859
+ else if ((candidate.nodeType !== RDFParser.nodeType.ELEMENT &&
1860
+ candidate.nodeType !== RDFParser.nodeType.TEXT &&
1861
+ candidate.nodeType !== RDFParser.nodeType.CDATA_SECTION) ||
1862
+ ((candidate.nodeType === RDFParser.nodeType.TEXT ||
1863
+ candidate.nodeType === RDFParser.nodeType.CDATA_SECTION) &&
1864
+ dom.childNodes.length !== 1)){
1865
+ frame.lastChild++;
1866
+ }
1867
+ else {
1868
+ // not a leaf
1869
+ frame.lastChild++;
1870
+ frame = this.buildFrame(pframe, dom.childNodes[frame.lastChild - 1]);
1871
+ break;
1872
+ }
1873
+ }
1874
+ }// while
1875
+ };
1876
+
2010
1877
  /**
2011
1878
  * Cleans out state from a previous parse run
2012
1879
  * @private
2013
1880
  */
2014
- this['cleanParser'] = function () {
2015
- this['bnodes'] = {};
2016
- this['why'] = null;
1881
+ this.cleanParser = function(){
1882
+ this.bnodes = {};
1883
+ this.why = null;
2017
1884
  };
2018
-
1885
+
2019
1886
  /**
2020
- * Builds scope frame
1887
+ * Builds scope frame
2021
1888
  * @private
2022
1889
  */
2023
- this['buildFrame'] = function (parent, element) {
2024
- var frame = this['frameFactory'](this,parent,element);
2025
- if (parent) {
2026
- frame['base'] = parent['base'];
2027
- frame['lang'] = parent['lang'];
2028
- }
2029
-
2030
- if ((!element) ||
2031
- (element['nodeType'] === RDFParser['nodeType']['TEXT']) ||
2032
- (element['nodeType'] === RDFParser['nodeType']['CDATA_SECTION'])) {
2033
- return frame;
2034
- }
2035
-
2036
- var attrs = element['attributes'];
2037
-
2038
- var base = element['getAttributeNode']("xml:base");
2039
- if (base) {
2040
- frame['base'] = base['nodeValue'];
2041
- element['removeAttribute']("xml:base");
2042
- }
2043
- var lang = element['getAttributeNode']("xml:lang");
2044
- if (lang) {
2045
- frame['lang'] = lang['nodeValue'];
2046
- element['removeAttribute']("xml:lang");
2047
- }
2048
-
2049
- // remove all extraneous xml and xmlns attributes
2050
- for (var x = attrs['length']-1; x >= 0; x--) {
2051
- if (attrs[x]['nodeName']['substr'](0,3) === "xml") {
2052
- if (attrs[x].name.slice(0,6) === 'xmlns:') {
2053
- var uri = attrs[x].nodeValue;
2054
- // alert('base for namespac attr:'+this.base);
2055
- if (this.base) {
2056
- uri = $rdf.Util.uri.join(uri, this.base);
1890
+ this.buildFrame = function(parent, element){
1891
+ var frame = this.frameFactory(this, parent, element);
1892
+ if (parent){
1893
+ frame.base = parent.base;
1894
+ frame.lang = parent.lang;
1895
+ }
1896
+ if (!element || element.nodeType === RDFParser.nodeType.TEXT ||
1897
+ element.nodeType === RDFParser.nodeType.CDATA_SECTION){
1898
+ return frame;
1899
+ }
1900
+ var attrs = element.attributes;
1901
+ var base = element.getAttributeNode("xml:base");
1902
+ if (base != null){
1903
+ frame.base = base.nodeValue;
1904
+ element.removeAttribute("xml:base");
1905
+ }
1906
+ var lang = element.getAttributeNode("xml:lang");
1907
+ if (lang != null){
1908
+ frame.lang = lang.nodeValue;
1909
+ element.removeAttribute("xml:lang");
1910
+ }
1911
+ // remove all extraneous xml and xmlns attributes
1912
+ for (var x = attrs.length - 1;x >= 0;x--){
1913
+ if (attrs[x].nodeName.substr(0, 3) === "xml"){
1914
+ if (attrs[x].name.slice(0, 6) === 'xmlns:'){
1915
+ var uri = attrs[x].nodeValue;// alert('base for namespac attr:'+this.base);
1916
+ if (this.base) uri = $rdf.Util.uri.join(uri, this.base);
1917
+ this.store.setPrefixForURI(attrs[x].name.slice(6), uri);
1918
+ }
1919
+ // alert('rdfparser: xml atribute: '+attrs[x].name) //@@
1920
+ element.removeAttributeNode(attrs[x]);
2057
1921
  }
2058
- this.store.setPrefixForURI(attrs[x].name.slice(6), uri);
2059
- }
2060
- //alert('rdfparser: xml atribute: '+attrs[x].name) //@@
2061
- element['removeAttributeNode'](attrs[x]);
2062
1922
  }
2063
- }
2064
- return frame;
1923
+ return frame;
2065
1924
  };
2066
- };
2067
1925
  };
2068
1926
  /**
2069
1927
  *
@@ -2265,6 +2123,8 @@ var LOG_implies_URI = "http://www.w3.org/2000/10/swap/log#implies";
2265
2123
  var INTEGER_DATATYPE = "http://www.w3.org/2001/XMLSchema#integer";
2266
2124
  var FLOAT_DATATYPE = "http://www.w3.org/2001/XMLSchema#double";
2267
2125
  var DECIMAL_DATATYPE = "http://www.w3.org/2001/XMLSchema#decimal";
2126
+ var DATE_DATATYPE = "http://www.w3.org/2001/XMLSchema#date";
2127
+ var DATETIME_DATATYPE = "http://www.w3.org/2001/XMLSchema#dateTime";
2268
2128
  var BOOLEAN_DATATYPE = "http://www.w3.org/2001/XMLSchema#boolean";
2269
2129
  var option_noregen = 0;
2270
2130
  var _notQNameChars = "\t\r\n !\"#$%&'()*.,+/;<=>?@[\\]^`{|}~";
@@ -2276,6 +2136,8 @@ var eof = new RegExp("^[ \\t]*(#[^\\n]*)?$", 'g');
2276
2136
  var ws = new RegExp("^[ \\t]*", 'g');
2277
2137
  var signed_integer = new RegExp("^[-+]?[0-9]+", 'g');
2278
2138
  var number_syntax = new RegExp("^([-+]?[0-9]+)(\\.[0-9]+)?(e[-+]?[0-9]+)?", 'g');
2139
+ var datetime_syntax = new RegExp('[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9](T[0-9][0-9]:[0-9][0-9](:[0-9][0-9](\\.[0-9]*)?)?)?Z?');
2140
+
2279
2141
  var digitstring = new RegExp("^[0-9]+", 'g');
2280
2142
  var interesting = new RegExp("[\\\\\\r\\n\\\"]", 'g');
2281
2143
  var langcode = new RegExp("^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?", 'g');
@@ -3355,23 +3217,38 @@ __SinkParser.prototype.nodeOrLiteral = function(str, i, res) {
3355
3217
  }
3356
3218
  var ch = str.charAt(i);
3357
3219
  if (("-+0987654321".indexOf(ch) >= 0)) {
3358
- number_syntax.lastIndex = 0;
3359
- var m = number_syntax.exec(str.slice(i));
3360
- if ((m == null)) {
3361
- throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad number syntax");
3362
- }
3363
- var j = ( i + number_syntax.lastIndex ) ;
3364
- var val = pyjslib_slice(str, i, j);
3365
- if ((val.indexOf("e") >= 0)) {
3366
- res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(FLOAT_DATATYPE)));
3367
- }
3368
- else if ((pyjslib_slice(str, i, j).indexOf(".") >= 0)) {
3369
- res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(DECIMAL_DATATYPE)));
3370
- }
3371
- else {
3372
- res.push(this._store.literal(parseInt(val), undefined, this._store.sym(INTEGER_DATATYPE)));
3373
- }
3374
- return j;
3220
+
3221
+ datetime_syntax.lastIndex = 0;
3222
+ var m = datetime_syntax.exec(str.slice(i));
3223
+ if ((m != null)) {
3224
+ // j = ( i + datetime_syntax.lastIndex ) ;
3225
+ var val = m[0];
3226
+ j = i + val.length;
3227
+ if ((val.indexOf("T") >= 0)) {
3228
+ res.push(this._store.literal(val, undefined, this._store.sym(DATETIME_DATATYPE)));
3229
+ } else {
3230
+ res.push(this._store.literal(val, undefined, this._store.sym(DATE_DATATYPE)));
3231
+ }
3232
+
3233
+ } else {
3234
+ number_syntax.lastIndex = 0;
3235
+ var m = number_syntax.exec(str.slice(i));
3236
+ if ((m == null)) {
3237
+ throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad number or date syntax");
3238
+ }
3239
+ j = ( i + number_syntax.lastIndex ) ;
3240
+ var val = pyjslib_slice(str, i, j);
3241
+ if ((val.indexOf("e") >= 0)) {
3242
+ res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(FLOAT_DATATYPE)));
3243
+ }
3244
+ else if ((pyjslib_slice(str, i, j).indexOf(".") >= 0)) {
3245
+ res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(DECIMAL_DATATYPE)));
3246
+ }
3247
+ else {
3248
+ res.push(this._store.literal(parseInt(val), undefined, this._store.sym(INTEGER_DATATYPE)));
3249
+ }
3250
+ };
3251
+ return j; // Where we have got up to
3375
3252
  }
3376
3253
  if ((str.charAt(i) == "\"")) {
3377
3254
  if ((pyjslib_slice(str, i, ( i + 3 ) ) == "\"\"\"")) {
@@ -3727,8 +3604,11 @@ $rdf.IndexedFormula.prototype.setPrefixForURI = function(prefix, nsuri) {
3727
3604
  //See http://dig.csail.mit.edu/cgi-bin/roundup.cgi/$rdf/issue227
3728
3605
  if(prefix=="tab" && this.namespaces["tab"]) {
3729
3606
  return;
3730
- }
3731
- this.namespaces[prefix] = nsuri
3607
+ } // There are files around with long badly generated prefixes like this
3608
+ if (prefix.slice(0,2) === 'ns' || prefix.slice(0,7) === 'default') {
3609
+ return;
3610
+ };
3611
+ this.namespaces[prefix] = nsuri;
3732
3612
  }
3733
3613
 
3734
3614
  // Deprocated ... name too generic
@@ -5315,495 +5195,546 @@ $rdf.SPARQLResultsInterpreter = function (xml, callback, doneCallback)
5315
5195
  return bindingList;
5316
5196
  //****END OF MAIN CODE*****
5317
5197
  }
5318
- // Joe Presbrey <presbrey@mit.edu>
5319
- // 2007-07-15
5320
- // 2010-08-08 TimBL folded in Kenny's WEBDAV
5321
- // 2010-12-07 TimBL addred local file write code
5322
-
5323
- $rdf.sparqlUpdate = function() {
5324
-
5325
- var anonymize = function (obj) {
5326
- return (obj.toNT().substr(0,2) == "_:")
5327
- ? "?" + obj.toNT().substr(2)
5328
- : obj.toNT();
5329
- }
5330
-
5331
- var anonymizeNT = function(stmt) {
5332
- return anonymize(stmt.subject) + " " +
5333
- anonymize(stmt.predicate) + " " +
5334
- anonymize(stmt.object) + " .";
5335
- }
5336
-
5337
- var sparql = function(store) {
5338
- this.store = store;
5339
- this.ifps = {};
5340
- this.fps = {};
5341
- this.ns = {};
5342
- this.ns.link = $rdf.Namespace("http://www.w3.org/2007/ont/link#");
5343
- this.ns.http = $rdf.Namespace("http://www.w3.org/2007/ont/http#");
5344
- this.ns.httph = $rdf.Namespace("http://www.w3.org/2007/ont/httph#");
5345
- this.ns.rdf = $rdf.Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
5346
- this.ns.rdfs = $rdf.Namespace("http://www.w3.org/2000/01/rdf-schema#");
5347
- this.ns.rdf = $rdf.Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
5348
- this.ns.owl = $rdf.Namespace("http://www.w3.org/2002/07/owl#");
5349
- }
5350
-
5351
-
5352
- // Returns The method string SPARQL or DAV or LOCALFILE or false if known, undefined if not known.
5353
- //
5354
- // Files have to have a specific annotaton that they are machine written, for safety.
5355
- // We don't actually check for write access on files.
5356
- //
5357
- sparql.prototype.editable = function(uri, kb) {
5358
- if (!uri) return false; // Eg subject is bnode, no known doc to write to
5359
- if (!kb) kb = tabulator.kb;
5360
-
5361
- if (uri.slice(0,8) == 'file:///') {
5362
- if (kb.holds(kb.sym(uri), tabulator.ns.rdf('type'), tabulator.ns.link('MachineEditableDocument')))
5363
- return 'LOCALFILE';
5364
- var sts = kb.statementsMatching(kb.sym(uri),undefined,undefined);
5365
-
5366
- tabulator.log.warn("sparql.editable: Not MachineEditableDocument file "+uri+"\n");
5367
- tabulator.log.warn(sts.map(function(x){return x.toNT();}).join('\n'))
5368
- return false;
5369
- //@@ Would be nifty of course to see whether we actually have write acess first.
5370
- }
5371
-
5372
- var request;
5373
- var definitive = false;
5374
- var requests = kb.each(undefined, this.ns.link("requestedURI"), $rdf.Util.uri.docpart(uri));
5375
- for (var r=0; r<requests.length; r++) {
5376
- request = requests[r];
5377
- if (request !== undefined) {
5378
- var response = kb.any(request, this.ns.link("response"));
5379
- if (request !== undefined) {
5380
- var author_via = kb.each(response, this.ns.httph("ms-author-via"));
5381
- if (author_via.length) {
5382
- for (var i = 0; i < author_via.length; i++) {
5383
- var method = author_via[i].value.trim();
5384
- if (method.indexOf('SPARQL') >=0 ) return 'SPARQL';
5385
- if (method.indexOf('DAV') >=0 ) return 'DAV';
5386
- // if (author_via[i].value == "SPARQL" || author_via[i].value == "DAV")
5387
- // dump("sparql.editable: Success for "+uri+": "+author_via[i] +"\n");
5388
- //return author_via[i].value;
5389
-
5390
- }
5391
- }
5392
- var status = kb.each(response, this.ns.http("status"));
5393
- if (status.length) {
5394
- for (var i = 0; i < status.length; i++) {
5395
- if (status[i] == 200 || status[i] == 404) {
5396
- definitive = true;
5397
- // return false; // A definitive answer
5398
- }
5399
- }
5400
- }
5401
- } else {
5402
- tabulator.log.warn("sparql.editable: No response for "+uri+"\n");
5403
- }
5404
- }
5405
- }
5406
- if (requests.length == 0) {
5407
- tabulator.log.warn("sparql.editable: No request for "+uri+"\n");
5408
- } else {
5409
- if (definitive) return false; // We have got a request and it did NOT say editable => not editable
5410
- };
5411
-
5412
- tabulator.log.warn("sparql.editable: inconclusive for "+uri+"\n");
5413
- return undefined; // We don't know (yet) as we haven't had a response (yet)
5414
- }
5415
-
5416
- /////////// The identification of bnodes
5417
-
5418
- sparql.prototype._statement_bnodes = function(st) {
5419
- return [st.subject, st.predicate, st.object].filter(function(x){return x.isBlank});
5420
- }
5421
-
5422
- sparql.prototype._statement_array_bnodes = function(sts) {
5423
- var bnodes = [];
5424
- for (var i=0; i<sts.length;i++) bnodes = bnodes.concat(this._statement_bnodes(sts[i]));
5425
- bnodes.sort(); // in place sort - result may have duplicates
5426
- bnodes2 = [];
5427
- for (var j=0; j<bnodes.length; j++)
5428
- if (j==0 || !bnodes[j].sameTermAs(bnodes[j-1])) bnodes2.push(bnodes[j]);
5429
- return bnodes2;
5430
- }
5431
-
5432
- sparql.prototype._cache_ifps = function() {
5433
- // Make a cached list of [Inverse-]Functional properties
5434
- // Call this once before calling context_statements
5435
- this.ifps = {};
5436
- var a = this.store.each(undefined, this.ns.rdf('type'), this.ns.owl('InverseFunctionalProperty'))
5437
- for (var i=0; i<a.length; i++) {
5438
- this.ifps[a[i].uri] = true;
5439
- }
5440
- this.fps = {};
5441
- var a = this.store.each(undefined, this.ns.rdf('type'), this.ns.owl('FunctionalProperty'))
5442
- for (var i=0; i<a.length; i++) {
5443
- this.fps[a[i].uri] = true;
5444
- }
5445
- }
5446
-
5447
- sparql.prototype._bnode_context2 = function(x, source, depth) {
5448
- // Return a list of statements which indirectly identify a node
5449
- // Depth > 1 if try further indirection.
5450
- // Return array of statements (possibly empty), or null if failure
5451
- var sts = this.store.statementsMatching(undefined, undefined, x, source); // incoming links
5452
- for (var i=0; i<sts.length; i++) {
5453
- if (this.fps[sts[i].predicate.uri]) {
5454
- var y = sts[i].subject;
5455
- if (!y.isBlank)
5456
- return [ sts[i] ];
5457
- if (depth) {
5458
- var res = this._bnode_context2(y, source, depth-1);
5459
- if (res != null)
5460
- return res.concat([ sts[i] ]);
5461
- }
5462
- }
5463
- }
5464
- var sts = this.store.statementsMatching(x, undefined, undefined, source); // outgoing links
5465
- for (var i=0; i<sts.length; i++) {
5466
- if (this.ifps[sts[i].predicate.uri]) {
5467
- var y = sts[i].object;
5468
- if (!y.isBlank)
5469
- return [ sts[i] ];
5470
- if (depth) {
5471
- var res = this._bnode_context2(y, source, depth-1);
5472
- if (res != undefined)
5473
- return res.concat([ sts[i] ]);
5474
- }
5475
- }
5476
- }
5477
- return null; // Failure
5478
- }
5479
-
5480
-
5481
- sparql.prototype._bnode_context = function(x, source) {
5482
- // Return a list of statements which indirectly identify a node
5483
- // Breadth-first
5484
- for (var depth = 0; depth < 3; depth++) { // Try simple first
5485
- var con = this._bnode_context2(x, source, depth);
5486
- if (con != null) return con;
5487
- }
5488
- throw ('Unable to uniquely identify bnode: '+ x.toNT());
5489
- }
5490
-
5491
- sparql.prototype._bnode_context = function(bnodes) {
5492
- var context = [];
5493
- if (bnodes.length) {
5494
- if (this.store.statementsMatching(st.subject.isBlank?undefined:st.subject,
5495
- st.predicate.isBlank?undefined:st.predicate,
5496
- st.object.isBlank?undefined:st.object,
5497
- st.why).length <= 1) {
5498
- context = context.concat(st);
5499
- } else {
5500
- this._cache_ifps();
5501
- for (x in bnodes) {
5502
- context = context.concat(this._bnode_context(bnodes[x], st.why));
5503
- }
5504
- }
5505
- }
5506
- return context;
5507
- }
5508
-
5509
- sparql.prototype._statement_context = function(st) {
5510
- var bnodes = this._statement_bnodes(st);
5511
- return this._bnode_context(bnodes);
5512
- }
5513
-
5514
- sparql.prototype._context_where = function(context) {
5515
- return (context == undefined || context.length == 0)
5516
- ? ""
5517
- : "WHERE { " + context.map(anonymizeNT).join("\n") + " }\n";
5518
- }
5519
-
5520
- sparql.prototype._fire = function(uri, query, callback) {
5521
- if (!uri) throw "No URI given for remote editing operation: "+query;
5522
- tabulator.log.info("sparql: sending update to <"+uri+">\n query="+query+"\n");
5523
- var xhr = $rdf.Util.XMLHTTPFactory();
5524
-
5525
- xhr.onreadystatechange = function() {
5526
- //dump("SPARQL update ready state for <"+uri+"> readyState="+xhr.readyState+"\n"+query+"\n");
5527
- if (xhr.readyState == 4) {
5528
- var success = (!xhr.status || (xhr.status >= 200 && xhr.status < 300));
5529
- if (!success) tabulator.log.error("sparql: update failed for <"+uri+"> status="+
5530
- xhr.status+", "+xhr.statusText+", body length="+xhr.responseText.length+"\n for query: "+query);
5531
- else tabulator.log.debug("sparql: update Ok for <"+uri+">");
5532
- callback(uri, success, xhr.responseText);
5533
- }
5534
- }
5535
-
5536
- if(!tabulator.isExtension) {
5537
- try {
5538
- $rdf.Util.enablePrivilege("UniversalBrowserRead")
5539
- } catch(e) {
5540
- alert("Failed to get privileges: " + e)
5541
- }
5542
- }
5543
-
5544
- xhr.open('POST', uri, true); // async=true
5545
- xhr.setRequestHeader('Content-type', 'application/sparql-update');
5546
- xhr.send(query);
5547
- }
5548
-
5549
- // This does NOT update the statement.
5550
- // It returns an object whcih includes
5551
- // function which can be used to change the object of the statement.
5552
- //
5553
- sparql.prototype.update_statement = function(statement) {
5554
- if (statement && statement.why == undefined) return;
5555
-
5556
- var sparql = this;
5557
- var context = this._statement_context(statement);
5558
-
5559
- return {
5560
- statement: statement?[statement.subject, statement.predicate, statement.object, statement.why]:undefined,
5561
- statementNT: statement?anonymizeNT(statement):undefined,
5562
- where: sparql._context_where(context),
5563
-
5564
- set_object: function(obj, callback) {
5565
- query = this.where;
5566
- query += "DELETE DATA { " + this.statementNT + " } ;\n";
5567
- query += "INSERT DATA { " +
5568
- anonymize(this.statement[0]) + " " +
5569
- anonymize(this.statement[1]) + " " +
5570
- anonymize(obj) + " " + " . }\n";
5571
-
5572
- sparql._fire(this.statement[3].uri, query, callback);
5573
- }
5574
- }
5575
- }
5576
-
5577
- sparql.prototype.insert_statement = function(st, callback) {
5578
- var st0 = st instanceof Array ? st[0] : st;
5579
- var query = this._context_where(this._statement_context(st0));
5580
-
5581
- if (st instanceof Array) {
5582
- var stText="";
5583
- for (var i=0;i<st.length;i++) stText+=st[i]+'\n';
5584
- query += "INSERT DATA { " + stText + " }\n";
5585
- } else {
5586
- query += "INSERT DATA { " +
5587
- anonymize(st.subject) + " " +
5588
- anonymize(st.predicate) + " " +
5589
- anonymize(st.object) + " " + " . }\n";
5590
- }
5591
-
5592
- this._fire(st0.why.uri, query, callback);
5593
- }
5594
-
5595
- sparql.prototype.delete_statement = function(st, callback) {
5596
- var query = this._context_where(this._statement_context(st));
5597
-
5598
- query += "DELETE DATA { " + anonymizeNT(st) + " }\n";
5599
-
5600
- this._fire(st instanceof Array?st[0].why.uri:st.why.uri, query, callback);
5601
- }
5602
-
5603
- // This high-level function updates the local store iff the web is changed successfully.
5604
- //
5605
- // - deletions, insertions may be undefined or single statements or lists or formulae.
5606
- //
5607
- // - callback is called as callback(uri, success, errorbody)
5608
- //
5609
- sparql.prototype.update = function(deletions, insertions, callback) {
5610
- var kb = this.store;
5611
- tabulator.log.info("update called")
5612
- var ds = deletions == undefined ? []
5613
- : deletions instanceof $rdf.IndexedFormula ? deletions.statements
5614
- : deletions instanceof Array ? deletions : [ deletions ];
5615
- var is = insertions == undefined? []
5616
- : insertions instanceof $rdf.IndexedFormula ? insertions.statements
5617
- : insertions instanceof Array ? insertions : [ insertions ];
5618
- if (! (ds instanceof Array)) throw "Type Error "+(typeof ds)+": "+ds;
5619
- if (! (is instanceof Array)) throw "Type Error "+(typeof is)+": "+is;
5620
- var doc = ds.length ? ds[0].why : is[0].why;
5621
-
5622
- ds.map(function(st){if (!doc.sameTerm(st.why)) throw "sparql update: destination "+doc+" inconsistent with ds "+st.why;});
5623
- is.map(function(st){if (!doc.sameTerm(st.why)) throw "sparql update: destination = "+doc+" inconsistent with st.why ="+st.why;});
5624
-
5625
- var protocol = this.editable(doc.uri, kb);
5626
- if (!protocol) throw "Can't make changes in uneditable "+doc;
5627
-
5628
- if (protocol.indexOf('SPARQL') >=0) {
5629
- var bnodes = []
5630
- if (ds.length) bnodes = this._statement_array_bnodes(ds);
5631
- if (is.length) bnodes = bnodes.concat(this._statement_array_bnodes(is));
5632
- var context = this._bnode_context(bnodes);
5633
- var whereClause = this._context_where(context);
5634
- var query = ""
5635
- if (whereClause.length) { // Is there a WHERE clause?
5636
- if (ds.length) {
5637
- query += "DELETE { ";
5638
- for (var i=0; i<ds.length;i++) query+= anonymizeNT(ds[i])+"\n";
5639
- query += " }\n";
5640
- }
5641
- if (is.length) {
5642
- query += "INSERT { ";
5643
- for (var i=0; i<is.length;i++) query+= anonymizeNT(is[i])+"\n";
5644
- query += " }\n";
5645
- }
5646
- query += whereClause;
5647
- } else { // no where clause
5648
- if (ds.length) {
5649
- query += "DELETE DATA { ";
5650
- for (var i=0; i<ds.length;i++) query+= anonymizeNT(ds[i])+"\n";
5651
- query += " } \n";
5652
- }
5653
- if (is.length) {
5654
- if (ds.length) query += " ; ";
5655
- query += "INSERT DATA { ";
5656
- for (var i=0; i<is.length;i++) query+= anonymizeNT(is[i])+"\n";
5657
- query += " }\n";
5658
- }
5659
- }
5660
- this._fire(doc.uri, query,
5661
- function(uri, success, body) {
5662
- tabulator.log.info("\t sparql: Return success="+success+" for query "+query+"\n");
5663
- if (success) {
5664
- for (var i=0; i<ds.length;i++)
5665
- try { kb.remove(ds[i]) } catch(e) {
5666
- callback(uri, false,
5667
- "sparqlUpdate: Remote OK but error deleting statemmnt "+
5668
- ds[i] + " from local store:\n" + e)
5669
- }
5670
- for (var i=0; i<is.length;i++)
5671
- kb.add(is[i].subject, is[i].predicate, is[i].object, doc);
5672
- }
5673
- callback(uri, success, body);
5674
- });
5675
-
5676
- } else if (protocol.indexOf('DAV') >=0) {
5677
-
5678
- // The code below is derived from Kenny's UpdateCenter.js
5679
- var documentString;
5680
- var request = kb.any(doc, this.ns.link("request"));
5681
- if (!request) throw "No record of our HTTP GET request for document: "+doc; //should not happen
5682
- var response = kb.any(request, this.ns.link("response"));
5683
- if (!response) return null; // throw "No record HTTP GET response for document: "+doc;
5684
- var content_type = kb.the(response, this.ns.httph("content-type")).value;
5685
-
5686
- //prepare contents of revised document
5687
- var newSts = kb.statementsMatching(undefined, undefined, undefined, doc).slice(); // copy!
5688
- for (var i=0;i<ds.length;i++) $rdf.Util.RDFArrayRemove(newSts, ds[i]);
5689
- for (var i=0;i<is.length;i++) newSts.push(is[i]);
5690
-
5691
- //serialize to te appropriate format
5692
- var sz = $rdf.Serializer(kb);
5693
- sz.suggestNamespaces(kb.namespaces);
5694
- sz.setBase(doc.uri);//?? beware of this - kenny (why? tim)
5695
- switch(content_type){
5696
- case 'application/rdf+xml':
5697
- documentString = sz.statementsToXML(newSts);
5698
- break;
5699
- case 'text/n3':
5700
- case 'text/turtle':
5701
- case 'application/x-turtle': // Legacy
5702
- case 'application/n3': // Legacy
5703
- documentString = sz.statementsToN3(newSts);
5704
- break;
5705
- default:
5706
- throw "Content-type "+content_type +" not supported for data write";
5707
- }
5708
-
5709
- // Write the new version back
5710
-
5711
- var candidateTarget = kb.the(response, this.ns.httph("content-location"));
5712
- if (candidateTarget) targetURI = Util.uri.join(candidateTarget.value, targetURI);
5713
- var xhr = Util.XMLHTTPFactory();
5714
- xhr.onreadystatechange = function (){
5715
- if (xhr.readyState == 4){
5716
- //formula from sparqlUpdate.js, what about redirects?
5717
- var success = (!xhr.status || (xhr.status >= 200 && xhr.status < 300));
5718
- if (success) {
5719
- for (var i=0; i<ds.length;i++) kb.remove(ds[i]);
5720
- for (var i=0; i<is.length;i++)
5721
- kb.add(is[i].subject, is[i].predicate, is[i].object, doc);
5722
- }
5723
- callback(doc.uri, success, xhr.responseText);
5724
- }
5725
- };
5726
- xhr.open('PUT', targetURI, true);
5727
- //assume the server does PUT content-negotiation.
5728
- xhr.setRequestHeader('Content-type', content_type);//OK?
5729
- xhr.send(documentString);
5730
-
5731
- } else if (protocol.indexOf('LOCALFILE') >=0) {
5732
- try {
5733
- tabulator.log.info("Writing back to local file\n");
5734
- // See http://simon-jung.blogspot.com/2007/10/firefox-extension-file-io.html
5735
- //prepare contents of revised document
5736
- var newSts = kb.statementsMatching(undefined, undefined, undefined, doc).slice(); // copy!
5737
- for (var i=0;i<ds.length;i++) $rdf.Util.RDFArrayRemove(newSts, ds[i]);
5738
- for (var i=0;i<is.length;i++) newSts.push(is[i]);
5739
-
5740
- //serialize to the appropriate format
5741
- var documentString;
5742
- var sz = $rdf.Serializer(kb);
5743
- sz.suggestNamespaces(kb.namespaces);
5744
- sz.setBase(doc.uri);//?? beware of this - kenny (why? tim)
5745
- var dot = doc.uri.lastIndexOf('.');
5746
- if (dot < 1) throw "Rewriting file: No filename extension: "+doc.uri;
5747
- var ext = doc.uri.slice(dot+1);
5748
- switch(ext){
5749
- case 'rdf':
5750
- case 'owl': // Just my experence ...@@ we should keep the format in which it was parsed
5751
- case 'xml':
5752
- documentString = sz.statementsToXML(newSts);
5753
- break;
5754
- case 'n3':
5755
- case 'nt':
5756
- case 'ttl':
5757
- documentString = sz.statementsToN3(newSts);
5758
- break;
5759
- default:
5760
- throw "File extension ."+ext +" not supported for data write";
5761
- }
5762
-
5763
- // Write the new version back
5764
-
5765
- //create component for file writing
5766
- dump("Writing back: <<<"+documentString+">>>\n")
5767
- var filename = doc.uri.slice(7); // chop off file:// leaving /path
5768
- //tabulator.log.warn("Writeback: Filename: "+filename+"\n")
5769
- var file = Components.classes["@mozilla.org/file/local;1"]
5770
- .createInstance(Components.interfaces.nsILocalFile);
5771
- file.initWithPath(filename);
5772
- if(!file.exists()) throw "Rewriting file <"+doc.uri+"> but it does not exist!";
5773
-
5774
- //{
5775
- //file.create( Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 420);
5776
- //}
5777
- //create file output stream and use write/create/truncate mode
5778
- //0x02 writing, 0x08 create file, 0x20 truncate length if exist
5779
- var stream = Components.classes["@mozilla.org/network/file-output-stream;1"]
5780
- .createInstance(Components.interfaces.nsIFileOutputStream);
5781
-
5782
- stream.init(file, 0x02 | 0x08 | 0x20, 0666, 0);
5783
-
5784
- //write data to file then close output stream
5785
- stream.write(documentString, documentString.length);
5786
- stream.close();
5787
-
5788
- for (var i=0; i<ds.length;i++) kb.remove(ds[i]);
5789
- for (var i=0; i<is.length;i++)
5790
- kb.add(is[i].subject, is[i].predicate, is[i].object, doc);
5791
-
5792
- callback(doc.uri, true, ""); // success!
5793
- } catch(e) {
5794
- callback(doc.uri, false,
5795
- "Exception trying to write back file <"+doc.uri+">\n"+
5796
- tabulator.Util.stackString(e))
5797
- }
5798
-
5799
- } else throw "Unhandled edit method: '"+protocol+"' for "+doc;
5800
- };
5801
-
5802
-
5803
-
5804
- return sparql;
5805
-
5806
- }();
5198
+ // Joe Presbrey <presbrey@mit.edu>
5199
+ // 2007-07-15
5200
+ // 2010-08-08 TimBL folded in Kenny's WEBDAV
5201
+ // 2010-12-07 TimBL addred local file write code
5202
+
5203
+ $rdf.sparqlUpdate = function() {
5204
+
5205
+ var anonymize = function (obj) {
5206
+ return (obj.toNT().substr(0,2) == "_:")
5207
+ ? "?" + obj.toNT().substr(2)
5208
+ : obj.toNT();
5209
+ }
5210
+
5211
+ var anonymizeNT = function(stmt) {
5212
+ return anonymize(stmt.subject) + " " +
5213
+ anonymize(stmt.predicate) + " " +
5214
+ anonymize(stmt.object) + " .";
5215
+ }
5216
+
5217
+ var sparql = function(store) {
5218
+ this.store = store;
5219
+ this.ifps = {};
5220
+ this.fps = {};
5221
+ this.ns = {};
5222
+ this.ns.link = $rdf.Namespace("http://www.w3.org/2007/ont/link#");
5223
+ this.ns.http = $rdf.Namespace("http://www.w3.org/2007/ont/http#");
5224
+ this.ns.httph = $rdf.Namespace("http://www.w3.org/2007/ont/httph#");
5225
+ this.ns.rdf = $rdf.Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
5226
+ this.ns.rdfs = $rdf.Namespace("http://www.w3.org/2000/01/rdf-schema#");
5227
+ this.ns.rdf = $rdf.Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
5228
+ this.ns.owl = $rdf.Namespace("http://www.w3.org/2002/07/owl#");
5229
+ }
5230
+
5231
+
5232
+ // Returns The method string SPARQL or DAV or LOCALFILE or false if known, undefined if not known.
5233
+ //
5234
+ // Files have to have a specific annotaton that they are machine written, for safety.
5235
+ // We don't actually check for write access on files.
5236
+ //
5237
+ sparql.prototype.editable = function(uri, kb) {
5238
+ if (!uri) return false; // Eg subject is bnode, no known doc to write to
5239
+ if (!kb) kb = tabulator.kb;
5240
+
5241
+ if (uri.slice(0,8) == 'file:///') {
5242
+ if (kb.holds(kb.sym(uri), tabulator.ns.rdf('type'), tabulator.ns.link('MachineEditableDocument')))
5243
+ return 'LOCALFILE';
5244
+ var sts = kb.statementsMatching(kb.sym(uri),undefined,undefined);
5245
+
5246
+ tabulator.log.warn("sparql.editable: Not MachineEditableDocument file "+uri+"\n");
5247
+ tabulator.log.warn(sts.map(function(x){return x.toNT();}).join('\n'))
5248
+ return false;
5249
+ //@@ Would be nifty of course to see whether we actually have write acess first.
5250
+ }
5251
+
5252
+ var request;
5253
+ var definitive = false;
5254
+ var requests = kb.each(undefined, this.ns.link("requestedURI"), $rdf.uri.docpart(uri));
5255
+ for (var r=0; r<requests.length; r++) {
5256
+ request = requests[r];
5257
+ if (request !== undefined) {
5258
+ var response = kb.any(request, this.ns.link("response"));
5259
+ if (request !== undefined) {
5260
+ var author_via = kb.each(response, this.ns.httph("ms-author-via"));
5261
+ if (author_via.length) {
5262
+ for (var i = 0; i < author_via.length; i++) {
5263
+ var method = author_via[i].value.trim();
5264
+ if (method.indexOf('SPARQL') >=0 ) return 'SPARQL';
5265
+ if (method.indexOf('DAV') >=0 ) return 'DAV';
5266
+ // if (author_via[i].value == "SPARQL" || author_via[i].value == "DAV")
5267
+ // dump("sparql.editable: Success for "+uri+": "+author_via[i] +"\n");
5268
+ //return author_via[i].value;
5269
+
5270
+ }
5271
+ }
5272
+ var status = kb.each(response, this.ns.http("status"));
5273
+ if (status.length) {
5274
+ for (var i = 0; i < status.length; i++) {
5275
+ if (status[i] == 200 || status[i] == 404) {
5276
+ definitive = true;
5277
+ // return false; // A definitive answer
5278
+ }
5279
+ }
5280
+ }
5281
+ } else {
5282
+ tabulator.log.warn("sparql.editable: No response for "+uri+"\n");
5283
+ }
5284
+ }
5285
+ }
5286
+ if (requests.length == 0) {
5287
+ tabulator.log.warn("sparql.editable: No request for "+uri+"\n");
5288
+ } else {
5289
+ if (definitive) return false; // We have got a request and it did NOT say editable => not editable
5290
+ };
5291
+
5292
+ tabulator.log.warn("sparql.editable: inconclusive for "+uri+"\n");
5293
+ return undefined; // We don't know (yet) as we haven't had a response (yet)
5294
+ }
5295
+
5296
+ /////////// The identification of bnodes
5297
+
5298
+ sparql.prototype._statement_bnodes = function(st) {
5299
+ return [st.subject, st.predicate, st.object].filter(function(x){return x.isBlank});
5300
+ }
5301
+
5302
+ sparql.prototype._statement_array_bnodes = function(sts) {
5303
+ var bnodes = [];
5304
+ for (var i=0; i<sts.length;i++) bnodes = bnodes.concat(this._statement_bnodes(sts[i]));
5305
+ bnodes.sort(); // in place sort - result may have duplicates
5306
+ bnodes2 = [];
5307
+ for (var j=0; j<bnodes.length; j++)
5308
+ if (j==0 || !bnodes[j].sameTermAs(bnodes[j-1])) bnodes2.push(bnodes[j]);
5309
+ return bnodes2;
5310
+ }
5311
+
5312
+ sparql.prototype._cache_ifps = function() {
5313
+ // Make a cached list of [Inverse-]Functional properties
5314
+ // Call this once before calling context_statements
5315
+ this.ifps = {};
5316
+ var a = this.store.each(undefined, this.ns.rdf('type'), this.ns.owl('InverseFunctionalProperty'))
5317
+ for (var i=0; i<a.length; i++) {
5318
+ this.ifps[a[i].uri] = true;
5319
+ }
5320
+ this.fps = {};
5321
+ var a = this.store.each(undefined, this.ns.rdf('type'), this.ns.owl('FunctionalProperty'))
5322
+ for (var i=0; i<a.length; i++) {
5323
+ this.fps[a[i].uri] = true;
5324
+ }
5325
+ }
5326
+
5327
+ sparql.prototype._bnode_context2 = function(x, source, depth) {
5328
+ // Return a list of statements which indirectly identify a node
5329
+ // Depth > 1 if try further indirection.
5330
+ // Return array of statements (possibly empty), or null if failure
5331
+ var sts = this.store.statementsMatching(undefined, undefined, x, source); // incoming links
5332
+ for (var i=0; i<sts.length; i++) {
5333
+ if (this.fps[sts[i].predicate.uri]) {
5334
+ var y = sts[i].subject;
5335
+ if (!y.isBlank)
5336
+ return [ sts[i] ];
5337
+ if (depth) {
5338
+ var res = this._bnode_context2(y, source, depth-1);
5339
+ if (res != null)
5340
+ return res.concat([ sts[i] ]);
5341
+ }
5342
+ }
5343
+ }
5344
+ var sts = this.store.statementsMatching(x, undefined, undefined, source); // outgoing links
5345
+ for (var i=0; i<sts.length; i++) {
5346
+ if (this.ifps[sts[i].predicate.uri]) {
5347
+ var y = sts[i].object;
5348
+ if (!y.isBlank)
5349
+ return [ sts[i] ];
5350
+ if (depth) {
5351
+ var res = this._bnode_context2(y, source, depth-1);
5352
+ if (res != undefined)
5353
+ return res.concat([ sts[i] ]);
5354
+ }
5355
+ }
5356
+ }
5357
+ return null; // Failure
5358
+ }
5359
+
5360
+
5361
+ sparql.prototype._bnode_context = function(x, source) {
5362
+ // Return a list of statements which indirectly identify a node
5363
+ // Breadth-first
5364
+ for (var depth = 0; depth < 3; depth++) { // Try simple first
5365
+ var con = this._bnode_context2(x, source, depth);
5366
+ if (con != null) return con;
5367
+ }
5368
+ throw ('Unable to uniquely identify bnode: '+ x.toNT());
5369
+ }
5370
+
5371
+ sparql.prototype._bnode_context = function(bnodes) {
5372
+ var context = [];
5373
+ if (bnodes.length) {
5374
+ if (this.store.statementsMatching(st.subject.isBlank?undefined:st.subject,
5375
+ st.predicate.isBlank?undefined:st.predicate,
5376
+ st.object.isBlank?undefined:st.object,
5377
+ st.why).length <= 1) {
5378
+ context = context.concat(st);
5379
+ } else {
5380
+ this._cache_ifps();
5381
+ for (x in bnodes) {
5382
+ context = context.concat(this._bnode_context(bnodes[x], st.why));
5383
+ }
5384
+ }
5385
+ }
5386
+ return context;
5387
+ }
5388
+
5389
+ sparql.prototype._statement_context = function(st) {
5390
+ var bnodes = this._statement_bnodes(st);
5391
+ return this._bnode_context(bnodes);
5392
+ }
5393
+
5394
+ sparql.prototype._context_where = function(context) {
5395
+ return (context == undefined || context.length == 0)
5396
+ ? ""
5397
+ : "WHERE { " + context.map(anonymizeNT).join("\n") + " }\n";
5398
+ }
5399
+
5400
+ sparql.prototype._fire = function(uri, query, callback) {
5401
+ if (!uri) throw "No URI given for remote editing operation: "+query;
5402
+ tabulator.log.info("sparql: sending update to <"+uri+">\n query="+query+"\n");
5403
+ var xhr = $rdf.Util.XMLHTTPFactory();
5404
+
5405
+ xhr.onreadystatechange = function() {
5406
+ //dump("SPARQL update ready state for <"+uri+"> readyState="+xhr.readyState+"\n"+query+"\n");
5407
+ if (xhr.readyState == 4) {
5408
+ var success = (!xhr.status || (xhr.status >= 200 && xhr.status < 300));
5409
+ if (!success) tabulator.log.error("sparql: update failed for <"+uri+"> status="+
5410
+ xhr.status+", "+xhr.statusText+", body length="+xhr.responseText.length+"\n for query: "+query);
5411
+ else tabulator.log.debug("sparql: update Ok for <"+uri+">");
5412
+ callback(uri, success, xhr.responseText);
5413
+ }
5414
+ }
5415
+
5416
+ if(!tabulator.isExtension) {
5417
+ try {
5418
+ $rdf.Util.enablePrivilege("UniversalBrowserRead")
5419
+ } catch(e) {
5420
+ alert("Failed to get privileges: " + e)
5421
+ }
5422
+ }
5423
+
5424
+ xhr.open('POST', uri, true); // async=true
5425
+ xhr.setRequestHeader('Content-type', 'application/sparql-update');
5426
+ xhr.send(query);
5427
+ }
5428
+
5429
+ // This does NOT update the statement.
5430
+ // It returns an object whcih includes
5431
+ // function which can be used to change the object of the statement.
5432
+ //
5433
+ sparql.prototype.update_statement = function(statement) {
5434
+ if (statement && statement.why == undefined) return;
5435
+
5436
+ var sparql = this;
5437
+ var context = this._statement_context(statement);
5438
+
5439
+ return {
5440
+ statement: statement?[statement.subject, statement.predicate, statement.object, statement.why]:undefined,
5441
+ statementNT: statement?anonymizeNT(statement):undefined,
5442
+ where: sparql._context_where(context),
5443
+
5444
+ set_object: function(obj, callback) {
5445
+ query = this.where;
5446
+ query += "DELETE DATA { " + this.statementNT + " } ;\n";
5447
+ query += "INSERT DATA { " +
5448
+ anonymize(this.statement[0]) + " " +
5449
+ anonymize(this.statement[1]) + " " +
5450
+ anonymize(obj) + " " + " . }\n";
5451
+
5452
+ sparql._fire(this.statement[3].uri, query, callback);
5453
+ }
5454
+ }
5455
+ }
5456
+
5457
+ sparql.prototype.insert_statement = function(st, callback) {
5458
+ var st0 = st instanceof Array ? st[0] : st;
5459
+ var query = this._context_where(this._statement_context(st0));
5460
+
5461
+ if (st instanceof Array) {
5462
+ var stText="";
5463
+ for (var i=0;i<st.length;i++) stText+=st[i]+'\n';
5464
+ query += "INSERT DATA { " + stText + " }\n";
5465
+ } else {
5466
+ query += "INSERT DATA { " +
5467
+ anonymize(st.subject) + " " +
5468
+ anonymize(st.predicate) + " " +
5469
+ anonymize(st.object) + " " + " . }\n";
5470
+ }
5471
+
5472
+ this._fire(st0.why.uri, query, callback);
5473
+ }
5474
+
5475
+ sparql.prototype.delete_statement = function(st, callback) {
5476
+
5477
+ var st0 = st instanceof Array ? st[0] : st;
5478
+ var query = this._context_where(this._statement_context(st0));
5479
+
5480
+ if (st instanceof Array) {
5481
+ var stText="";
5482
+ for (var i=0;i<st.length;i++) stText+=st[i]+'\n';
5483
+ query += "DELETE DATA { " + stText + " }\n";
5484
+ } else {
5485
+ query += "DELETE DATA { " +
5486
+ anonymize(st.subject) + " " +
5487
+ anonymize(st.predicate) + " " +
5488
+ anonymize(st.object) + " " + " . }\n";
5489
+ }
5490
+
5491
+ this._fire(st0.why.uri, query, callback);
5492
+ }
5493
+
5494
+ // This high-level function updates the local store iff the web is changed successfully.
5495
+ //
5496
+ // - deletions, insertions may be undefined or single statements or lists or formulae.
5497
+ //
5498
+ // - callback is called as callback(uri, success, errorbody)
5499
+ //
5500
+ sparql.prototype.update = function(deletions, insertions, callback) {
5501
+ var kb = this.store;
5502
+ tabulator.log.info("update called")
5503
+ var ds = deletions == undefined ? []
5504
+ : deletions instanceof $rdf.IndexedFormula ? deletions.statements
5505
+ : deletions instanceof Array ? deletions : [ deletions ];
5506
+ var is = insertions == undefined? []
5507
+ : insertions instanceof $rdf.IndexedFormula ? insertions.statements
5508
+ : insertions instanceof Array ? insertions : [ insertions ];
5509
+ if (! (ds instanceof Array)) throw "Type Error "+(typeof ds)+": "+ds;
5510
+ if (! (is instanceof Array)) throw "Type Error "+(typeof is)+": "+is;
5511
+ var doc = ds.length ? ds[0].why : is[0].why;
5512
+
5513
+ ds.map(function(st){if (!doc.sameTerm(st.why)) throw "sparql update: destination "+doc+" inconsistent with ds "+st.why;});
5514
+ is.map(function(st){if (!doc.sameTerm(st.why)) throw "sparql update: destination = "+doc+" inconsistent with st.why ="+st.why;});
5515
+
5516
+ var protocol = this.editable(doc.uri, kb);
5517
+ if (!protocol) throw "Can't make changes in uneditable "+doc;
5518
+
5519
+ if (protocol.indexOf('SPARQL') >=0) {
5520
+ var bnodes = []
5521
+ if (ds.length) bnodes = this._statement_array_bnodes(ds);
5522
+ if (is.length) bnodes = bnodes.concat(this._statement_array_bnodes(is));
5523
+ var context = this._bnode_context(bnodes);
5524
+ var whereClause = this._context_where(context);
5525
+ var query = ""
5526
+ if (whereClause.length) { // Is there a WHERE clause?
5527
+ if (ds.length) {
5528
+ query += "DELETE { ";
5529
+ for (var i=0; i<ds.length;i++) query+= anonymizeNT(ds[i])+"\n";
5530
+ query += " }\n";
5531
+ }
5532
+ if (is.length) {
5533
+ query += "INSERT { ";
5534
+ for (var i=0; i<is.length;i++) query+= anonymizeNT(is[i])+"\n";
5535
+ query += " }\n";
5536
+ }
5537
+ query += whereClause;
5538
+ } else { // no where clause
5539
+ if (ds.length) {
5540
+ query += "DELETE DATA { ";
5541
+ for (var i=0; i<ds.length;i++) query+= anonymizeNT(ds[i])+"\n";
5542
+ query += " } \n";
5543
+ }
5544
+ if (is.length) {
5545
+ if (ds.length) query += " ; ";
5546
+ query += "INSERT DATA { ";
5547
+ for (var i=0; i<is.length;i++) query+= anonymizeNT(is[i])+"\n";
5548
+ query += " }\n";
5549
+ }
5550
+ }
5551
+ this._fire(doc.uri, query,
5552
+ function(uri, success, body) {
5553
+ tabulator.log.info("\t sparql: Return success="+success+" for query "+query+"\n");
5554
+ if (success) {
5555
+ for (var i=0; i<ds.length;i++)
5556
+ try { kb.remove(ds[i]) } catch(e) {
5557
+ callback(uri, false,
5558
+ "sparqlUpdate: Remote OK but error deleting statemmnt "+
5559
+ ds[i] + " from local store:\n" + e)
5560
+ }
5561
+ for (var i=0; i<is.length;i++)
5562
+ kb.add(is[i].subject, is[i].predicate, is[i].object, doc);
5563
+ }
5564
+ callback(uri, success, body);
5565
+ });
5566
+
5567
+ } else if (protocol.indexOf('DAV') >=0) {
5568
+
5569
+ // The code below is derived from Kenny's UpdateCenter.js
5570
+ var documentString;
5571
+ var request = kb.any(doc, this.ns.link("request"));
5572
+ if (!request) throw "No record of our HTTP GET request for document: "+doc; //should not happen
5573
+ var response = kb.any(request, this.ns.link("response"));
5574
+ if (!response) return null; // throw "No record HTTP GET response for document: "+doc;
5575
+ var content_type = kb.the(response, this.ns.httph("content-type")).value;
5576
+
5577
+ //prepare contents of revised document
5578
+ var newSts = kb.statementsMatching(undefined, undefined, undefined, doc).slice(); // copy!
5579
+ for (var i=0;i<ds.length;i++) $rdf.Util.RDFArrayRemove(newSts, ds[i]);
5580
+ for (var i=0;i<is.length;i++) newSts.push(is[i]);
5581
+
5582
+ //serialize to te appropriate format
5583
+ var sz = $rdf.Serializer(kb);
5584
+ sz.suggestNamespaces(kb.namespaces);
5585
+ sz.setBase(doc.uri);//?? beware of this - kenny (why? tim)
5586
+ switch(content_type){
5587
+ case 'application/rdf+xml':
5588
+ documentString = sz.statementsToXML(newSts);
5589
+ break;
5590
+ case 'text/n3':
5591
+ case 'text/turtle':
5592
+ case 'application/x-turtle': // Legacy
5593
+ case 'application/n3': // Legacy
5594
+ documentString = sz.statementsToN3(newSts);
5595
+ break;
5596
+ default:
5597
+ throw "Content-type "+content_type +" not supported for data write";
5598
+ }
5599
+
5600
+ // Write the new version back
5601
+
5602
+ var candidateTarget = kb.the(response, this.ns.httph("content-location"));
5603
+ if (candidateTarget) targetURI = $rdf.uri.join(candidateTarget.value, targetURI);
5604
+ var xhr = $rdf.Util.XMLHTTPFactory();
5605
+ xhr.onreadystatechange = function (){
5606
+ if (xhr.readyState == 4){
5607
+ //formula from sparqlUpdate.js, what about redirects?
5608
+ var success = (!xhr.status || (xhr.status >= 200 && xhr.status < 300));
5609
+ if (success) {
5610
+ for (var i=0; i<ds.length;i++) kb.remove(ds[i]);
5611
+ for (var i=0; i<is.length;i++)
5612
+ kb.add(is[i].subject, is[i].predicate, is[i].object, doc);
5613
+ }
5614
+ callback(doc.uri, success, xhr.responseText);
5615
+ }
5616
+ };
5617
+ xhr.open('PUT', targetURI, true);
5618
+ //assume the server does PUT content-negotiation.
5619
+ xhr.setRequestHeader('Content-type', content_type);//OK?
5620
+ xhr.send(documentString);
5621
+
5622
+ } else if (protocol.indexOf('LOCALFILE') >=0) {
5623
+ try {
5624
+ tabulator.log.info("Writing back to local file\n");
5625
+ // See http://simon-jung.blogspot.com/2007/10/firefox-extension-file-io.html
5626
+ //prepare contents of revised document
5627
+ var newSts = kb.statementsMatching(undefined, undefined, undefined, doc).slice(); // copy!
5628
+ for (var i=0;i<ds.length;i++) $rdf.Util.RDFArrayRemove(newSts, ds[i]);
5629
+ for (var i=0;i<is.length;i++) newSts.push(is[i]);
5630
+
5631
+ //serialize to the appropriate format
5632
+ var documentString;
5633
+ var sz = $rdf.Serializer(kb);
5634
+ sz.suggestNamespaces(kb.namespaces);
5635
+ sz.setBase(doc.uri);//?? beware of this - kenny (why? tim)
5636
+ var dot = doc.uri.lastIndexOf('.');
5637
+ if (dot < 1) throw "Rewriting file: No filename extension: "+doc.uri;
5638
+ var ext = doc.uri.slice(dot+1);
5639
+ switch(ext){
5640
+ case 'rdf':
5641
+ case 'owl': // Just my experence ...@@ we should keep the format in which it was parsed
5642
+ case 'xml':
5643
+ documentString = sz.statementsToXML(newSts);
5644
+ break;
5645
+ case 'n3':
5646
+ case 'nt':
5647
+ case 'ttl':
5648
+ documentString = sz.statementsToN3(newSts);
5649
+ break;
5650
+ default:
5651
+ throw "File extension ."+ext +" not supported for data write";
5652
+ }
5653
+
5654
+ // Write the new version back
5655
+
5656
+ //create component for file writing
5657
+ dump("Writing back: <<<"+documentString+">>>\n")
5658
+ var filename = doc.uri.slice(7); // chop off file:// leaving /path
5659
+ //tabulator.log.warn("Writeback: Filename: "+filename+"\n")
5660
+ var file = Components.classes["@mozilla.org/file/local;1"]
5661
+ .createInstance(Components.interfaces.nsILocalFile);
5662
+ file.initWithPath(filename);
5663
+ if(!file.exists()) throw "Rewriting file <"+doc.uri+"> but it does not exist!";
5664
+
5665
+ //{
5666
+ //file.create( Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 420);
5667
+ //}
5668
+ //create file output stream and use write/create/truncate mode
5669
+ //0x02 writing, 0x08 create file, 0x20 truncate length if exist
5670
+ var stream = Components.classes["@mozilla.org/network/file-output-stream;1"]
5671
+ .createInstance(Components.interfaces.nsIFileOutputStream);
5672
+
5673
+ stream.init(file, 0x02 | 0x08 | 0x20, 0666, 0);
5674
+
5675
+ //write data to file then close output stream
5676
+ stream.write(documentString, documentString.length);
5677
+ stream.close();
5678
+
5679
+ for (var i=0; i<ds.length;i++) kb.remove(ds[i]);
5680
+ for (var i=0; i<is.length;i++)
5681
+ kb.add(is[i].subject, is[i].predicate, is[i].object, doc);
5682
+
5683
+ callback(doc.uri, true, ""); // success!
5684
+ } catch(e) {
5685
+ callback(doc.uri, false,
5686
+ "Exception trying to write back file <"+doc.uri+">\n"+
5687
+ tabulator.Util.stackString(e))
5688
+ }
5689
+
5690
+ } else throw "Unhandled edit method: '"+protocol+"' for "+doc;
5691
+ };
5692
+
5693
+ // This suitable for an inital creation of a document
5694
+ //
5695
+ sparql.prototype.put = function(doc, newSts, content_type, callback) {
5696
+
5697
+ var documentString;
5698
+ var kb = this.store;
5699
+
5700
+ //serialize to te appropriate format
5701
+ var sz = $rdf.Serializer(kb);
5702
+ sz.suggestNamespaces(kb.namespaces);
5703
+ sz.setBase(doc.uri);//?? beware of this - kenny (why? tim)
5704
+ switch(content_type){
5705
+ case 'application/rdf+xml':
5706
+ documentString = sz.statementsToXML(newSts);
5707
+ break;
5708
+ case 'text/n3':
5709
+ case 'text/turtle':
5710
+ case 'application/x-turtle': // Legacy
5711
+ case 'application/n3': // Legacy
5712
+ documentString = sz.statementsToN3(newSts);
5713
+ break;
5714
+ default:
5715
+ throw "Content-type "+content_type +" not supported for data PUT";
5716
+ }
5717
+
5718
+ var xhr = $rdf.Util.XMLHTTPFactory();
5719
+ xhr.onreadystatechange = function (){
5720
+ if (xhr.readyState == 4){
5721
+ //formula from sparqlUpdate.js, what about redirects?
5722
+ var success = (!xhr.status || (xhr.status >= 200 && xhr.status < 300));
5723
+ callback(doc.uri, success, xhr.responseText);
5724
+ }
5725
+ };
5726
+ xhr.open('PUT', doc.uri, true);
5727
+ //assume the server does PUT content-negotiation.
5728
+ xhr.setRequestHeader('Content-type', content_type);//OK?
5729
+ xhr.send(documentString);
5730
+
5731
+ };
5732
+
5733
+
5734
+
5735
+ return sparql;
5736
+
5737
+ }();
5807
5738
  $rdf.jsonParser = function() {
5808
5739
 
5809
5740
  return {
@@ -5858,950 +5789,952 @@ $rdf.jsonParser = function() {
5858
5789
  }
5859
5790
  }
5860
5791
  }();
5861
- /* Serialization of RDF Graphs
5862
- **
5863
- ** Tim Berners-Lee 2006
5864
- ** This is or was http://dig.csail.mit.edu/2005/ajar/ajaw/js/rdf/serialize.js
5865
- **
5866
- ** Bug: can't serialize http://data.semanticweb.org/person/abraham-bernstein/rdf
5867
- ** in XML (from mhausenblas)
5868
- */
5869
-
5870
- // @@@ Check the whole toStr thing tosee whetehr it still makes sense -- tbl
5871
- //
5872
- $rdf.Serializer = function() {
5873
-
5874
- var __Serializer = function( store ){
5875
- this.flags = "";
5876
- this.base = null;
5877
- this.prefixes = [];
5878
- this.keywords = ['a']; // The only one we generate at the moment
5879
- this.prefixchars = "abcdefghijklmnopqustuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
5880
- this.incoming = null; // Array not calculated yet
5881
- this.formulas = []; // remebering original formulae from hashes
5882
- this.store = store;
5883
-
5884
- /* pass */
5885
- }
5886
-
5887
- __Serializer.prototype.setBase = function(base)
5888
- { this.base = base };
5889
-
5890
- __Serializer.prototype.setFlags = function(flags)
5891
- { this.flags = flags?flags: '' };
5892
-
5893
-
5894
- __Serializer.prototype.toStr = function(x) {
5895
- var s = x.toNT();
5896
- if (x.termType == 'formula') {
5897
- this.formulas[s] = x; // remember as reverse does not work
5898
- }
5899
- return s;
5900
- };
5901
-
5902
- __Serializer.prototype.fromStr = function(s) {
5903
- if (s[0] == '{') {
5904
- var x = this.formulas[s];
5905
- if (!x) alert('No formula object for '+s)
5906
- return x;
5907
- }
5908
- return this.store.fromNT(s);
5909
- };
5910
-
5911
-
5912
-
5913
-
5914
-
5915
- /* Accumulate Namespaces
5916
- **
5917
- ** These are only hints. If two overlap, only one gets used
5918
- ** There is therefore no guarantee in general.
5919
- */
5920
-
5921
- __Serializer.prototype.suggestPrefix = function(prefix, uri) {
5922
- this.prefixes[uri] = prefix;
5923
- }
5924
-
5925
- // Takes a namespace -> prefix map
5926
- __Serializer.prototype.suggestNamespaces = function(namespaces) {
5927
- for (var px in namespaces) {
5928
- this.prefixes[namespaces[px]] = px;
5929
- }
5930
- }
5931
-
5932
- // Make up an unused prefix for a random namespace
5933
- __Serializer.prototype.makeUpPrefix = function(uri) {
5934
- var p = uri;
5935
- var namespaces = [];
5936
- var pok;
5937
-
5938
- function canUse(pp) {
5939
- if (namespaces[pp]) return false; // already used
5940
- this.prefixes[uri] = pp;
5941
- pok = pp;
5942
- return true
5943
- }
5944
- canUse = canUse.bind(this);
5945
- for (var ns in this.prefixes) {
5946
- namespaces[this.prefixes[ns]] = ns; // reverse index
5947
- }
5948
- if ('#/'.indexOf(p[p.length-1]) >= 0) p = p.slice(0, -1);
5949
- var slash = p.lastIndexOf('/');
5950
- if (slash >= 0) p = p.slice(slash+1);
5951
- var i = 0;
5952
- while (i < p.length)
5953
- if (this.prefixchars.indexOf(p[i])) i++; else break;
5954
- p = p.slice(0,i);
5955
- if (p.length < 6 && canUse(p)) return pok; // exact i sbest
5956
- if (canUse(p.slice(0,3))) return pok;
5957
- if (canUse(p.slice(0,2))) return pok;
5958
- if (canUse(p.slice(0,4))) return pok;
5959
- if (canUse(p.slice(0,1))) return pok;
5960
- if (canUse(p.slice(0,5))) return pok;
5961
- for (var i=0;; i++) if (canUse(p.slice(0,3)+i)) return pok;
5962
- }
5963
-
5964
-
5965
-
5966
- // Todo:
5967
- // - Sort the statements by subject, pred, object
5968
- // - do stuff about the docu first and then (or first) about its primary topic.
5969
-
5970
- __Serializer.prototype.rootSubjects = function(sts) {
5971
- var incoming = {};
5972
- var subjects = {};
5973
- var allBnodes = {};
5974
-
5975
- /* This scan is to find out which nodes will have to be the roots of trees
5976
- ** in the serialized form. This will be any symbols, and any bnodes
5977
- ** which hve more or less than one incoming arc, and any bnodes which have
5978
- ** one incoming arc but it is an uninterrupted loop of such nodes back to itself.
5979
- ** This should be kept linear time with repect to the number of statements.
5980
- ** Note it does not use any indexing of the store.
5981
- */
5982
-
5983
-
5984
- // $rdf.log.debug('serialize.js Find bnodes with only one incoming arc\n')
5985
- for (var i = 0; i<sts.length; i++) {
5986
- var st = sts[i];
5987
- [ st.subject, st.predicate, st.object].map(function(y){
5988
- if (y.termType =='bnode'){allBnodes[y.toNT()] = true}});
5989
- var x = sts[i].object;
5990
- if (!incoming.hasOwnProperty(x)) incoming[x] = [];
5991
- incoming[x].push(st.subject) // List of things which will cause this to be printed
5992
- var ss = subjects[this.toStr(st.subject)]; // Statements with this as subject
5993
- if (!ss) ss = [];
5994
- ss.push(st);
5995
- subjects[this.toStr(st.subject)] = ss; // Make hash. @@ too slow for formula?
5996
- // $rdf.log.debug(' sz potential subject: '+sts[i].subject)
5997
- }
5998
-
5999
- var roots = [];
6000
- for (var xNT in subjects) {
6001
- if (!subjects.hasOwnProperty(xNT)) continue;
6002
- var x = this.fromStr(xNT);
6003
- if ((x.termType != 'bnode') || !incoming[x] || (incoming[x].length != 1)){
6004
- roots.push(x);
6005
- //$rdf.log.debug(' sz actual subject -: ' + x)
6006
- continue;
6007
- }
6008
- }
6009
- this.incoming = incoming; // Keep for serializing @@ Bug for nested formulas
6010
-
6011
- //////////// New bit for CONNECTED bnode loops:frootshash
6012
-
6013
- // This scans to see whether the serialization is gpoing to lead to a bnode loop
6014
- // and at the same time accumulates a list of all bnodes mentioned.
6015
- // This is in fact a cut down N3 serialization
6016
- /*
6017
- // $rdf.log.debug('serialize.js Looking for connected bnode loops\n')
6018
- for (var i=0; i<sts.length; i++) { // @@TBL
6019
- // dump('\t'+sts[i]+'\n');
6020
- }
6021
- var doneBnodesNT = {};
6022
- function dummyPropertyTree(subject, subjects, rootsHash) {
6023
- // dump('dummyPropertyTree('+subject+'...)\n');
6024
- var sts = subjects[sz.toStr(subject)]; // relevant statements
6025
- for (var i=0; i<sts.length; i++) {
6026
- dummyObjectTree(sts[i].object, subjects, rootsHash);
6027
- }
6028
- }
6029
-
6030
- // Convert a set of statements into a nested tree of lists and strings
6031
- // @param force, "we know this is a root, do it anyway. It isn't a loop."
6032
- function dummyObjectTree(obj, subjects, rootsHash, force) {
6033
- // dump('dummyObjectTree('+obj+'...)\n');
6034
- if (obj.termType == 'bnode' && (subjects[sz.toStr(obj)] &&
6035
- (force || (rootsHash[obj.toNT()] == undefined )))) {// and there are statements
6036
- if (doneBnodesNT[obj.toNT()]) { // Ah-ha! a loop
6037
- throw "Serializer: Should be no loops "+obj;
6038
- }
6039
- doneBnodesNT[obj.toNT()] = true;
6040
- return dummyPropertyTree(obj, subjects, rootsHash);
6041
- }
6042
- return dummyTermToN3(obj, subjects, rootsHash);
6043
- }
6044
-
6045
- // Scan for bnodes nested inside lists too
6046
- function dummyTermToN3(expr, subjects, rootsHash) {
6047
- if (expr.termType == 'bnode') doneBnodesNT[expr.toNT()] = true;
6048
- // $rdf.log.debug('serialize: seen '+expr);
6049
- if (expr.termType == 'collection') {
6050
- for (i=0; i<expr.elements.length; i++) {
6051
- if (expr.elements[i].termType == 'bnode')
6052
- dummyObjectTree(expr.elements[i], subjects, rootsHash);
6053
- }
6054
- return;
6055
- }
6056
- }
6057
-
6058
- // The tree for a subject
6059
- function dummySubjectTree(subject, subjects, rootsHash) {
6060
- // dump('dummySubjectTree('+subject+'...)\n');
6061
- if (subject.termType == 'bnode' && !incoming[subject])
6062
- return dummyObjectTree(subject, subjects, rootsHash, true); // Anonymous bnode subject
6063
- dummyTermToN3(subject, subjects, rootsHash);
6064
- dummyPropertyTree(subject, subjects, rootsHash);
6065
- }
6066
- */
6067
- // Now do the scan using existing roots
6068
- // $rdf.log.debug('serialize.js Dummy serialize to check for missing nodes')
6069
- var rootsHash = {};
6070
- for (var i = 0; i< roots.length; i++) rootsHash[roots[i].toNT()] = true;
6071
- /*
6072
- for (var i=0; i<roots.length; i++) {
6073
- var root = roots[i];
6074
- dummySubjectTree(root, subjects, rootsHash);
6075
- }
6076
- // dump('Looking for mising bnodes...\n')
6077
-
6078
- // Now in new roots for anythig not acccounted for
6079
- // Now we check for any bndoes which have not been covered.
6080
- // Such bnodes must be in isolated rings of pure bnodes.
6081
- // They each have incoming link of 1.
6082
-
6083
- // $rdf.log.debug('serialize.js Looking for connected bnode loops\n')
6084
- for (;;) {
6085
- var bnt;
6086
- var found = null;
6087
- for (bnt in allBnodes) { // @@ Note: not repeatable. No canonicalisation
6088
- if (doneBnodesNT[bnt]) continue;
6089
- found = bnt; // Ah-ha! not covered
6090
- break;
6091
- }
6092
- if (found == null) break; // All done - no bnodes left out/
6093
- // dump('Found isolated bnode:'+found+'\n');
6094
- doneBnodesNT[bnt] = true;
6095
- var root = this.store.fromNT(found);
6096
- roots.push(root); // Add a new root
6097
- rootsHash[found] = true;
6098
- // $rdf.log.debug('isolated bnode:'+found+', subjects[found]:'+subjects[found]+'\n');
6099
- if (subjects[found] == undefined) {
6100
- for (var i=0; i<sts.length; i++) {
6101
- // dump('\t'+sts[i]+'\n');
6102
- }
6103
- throw "Isolated node should be a subject" +found;
6104
- }
6105
- dummySubjectTree(root, subjects, rootsHash); // trace out the ring
6106
- }
6107
- // dump('Done bnode adjustments.\n')
6108
- */
6109
- return {'roots':roots, 'subjects':subjects,
6110
- 'rootsHash': rootsHash, 'incoming': incoming};
6111
- }
6112
-
6113
- ////////////////////////////////////////////////////////
6114
-
6115
- __Serializer.prototype.toN3 = function(f) {
6116
- return this.statementsToN3(f.statements);
6117
- }
6118
-
6119
- __Serializer.prototype._notQNameChars = "\t\r\n !\"#$%&'()*.,+/;<=>?@[\\]^`{|}~";
6120
- __Serializer.prototype._notNameChars =
6121
- ( __Serializer.prototype._notQNameChars + ":" ) ;
6122
-
6123
-
6124
- __Serializer.prototype.statementsToN3 = function(sts) {
6125
- var indent = 4;
6126
- var width = 80;
6127
-
6128
- var namespaceCounts = []; // which have been used
6129
-
6130
- var predMap = {
6131
- 'http://www.w3.org/2002/07/owl#sameAs': '=',
6132
- 'http://www.w3.org/2000/10/swap/log#implies': '=>',
6133
- 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type': 'a'
6134
- }
6135
-
6136
-
6137
-
6138
-
6139
- ////////////////////////// Arrange the bits of text
6140
-
6141
- var spaces=function(n) {
6142
- var s='';
6143
- for(var i=0; i<n; i++) s+=' ';
6144
- return s
6145
- }
6146
-
6147
- var treeToLine = function(tree) {
6148
- var str = '';
6149
- for (var i=0; i<tree.length; i++) {
6150
- var branch = tree[i];
6151
- var s2 = (typeof branch == 'string') ? branch : treeToLine(branch);
6152
- if (i!=0 && s2 != ',' && s2 != ';' && s2 != '.') str += ' ';
6153
- str += s2;
6154
- }
6155
- return str;
6156
- }
6157
-
6158
- // Convert a nested tree of lists and strings to a string
6159
- var treeToString = function(tree, level) {
6160
- var str = '';
6161
- var lastLength = 100000;
6162
- if (!level) level = 0;
6163
- for (var i=0; i<tree.length; i++) {
6164
- var branch = tree[i];
6165
- if (typeof branch != 'string') {
6166
- var substr = treeToString(branch, level +1);
6167
- if (
6168
- substr.length < 10*(width-indent*level)
6169
- && substr.indexOf('"""') < 0) {// Don't mess up multiline strings
6170
- var line = treeToLine(branch);
6171
- if (line.length < (width-indent*level)) {
6172
- branch = ' '+line; // @@ Hack: treat as string below
6173
- substr = ''
6174
- }
6175
- }
6176
- if (substr) lastLength = 10000;
6177
- str += substr;
6178
- }
6179
- if (typeof branch == 'string') {
6180
- if (branch.length == '1' && str.slice(-1) == '\n') {
6181
- if (",.;".indexOf(branch) >=0) {
6182
- str = str.slice(0,-1) + branch + '\n'; // slip punct'n on end
6183
- lastLength += 1;
6184
- continue;
6185
- } else if ("])}".indexOf(branch) >=0) {
6186
- str = str.slice(0,-1) + ' ' + branch + '\n';
6187
- lastLength += 2;
6188
- continue;
6189
- }
6190
- }
6191
- if (lastLength < (indent*level+4)) { // continue
6192
- str = str.slice(0,-1) + ' ' + branch + '\n';
6193
- lastLength += branch.length + 1;
6194
- } else {
6195
- var line = spaces(indent*level) +branch;
6196
- str += line +'\n';
6197
- lastLength = line.length;
6198
- }
6199
-
6200
- } else { // not string
6201
- }
6202
- }
6203
- return str;
6204
- };
6205
-
6206
- ////////////////////////////////////////////// Structure for N3
6207
-
6208
-
6209
- // Convert a set of statements into a nested tree of lists and strings
6210
- function statementListToTree(statements) {
6211
- // print('Statement tree for '+statements.length);
6212
- var res = [];
6213
- var stats = this.rootSubjects(statements);
6214
- var roots = stats.roots;
6215
- var results = []
6216
- for (var i=0; i<roots.length; i++) {
6217
- var root = roots[i];
6218
- results.push(subjectTree(root, stats))
6219
- }
6220
- return results;
6221
- }
6222
- statementListToTree = statementListToTree.bind(this);
6223
-
6224
- // The tree for a subject
6225
- function subjectTree(subject, stats) {
6226
- if (subject.termType == 'bnode' && !stats.incoming[subject])
6227
- return objectTree(subject, stats, true).concat(["."]); // Anonymous bnode subject
6228
- return [ termToN3(subject, stats) ].concat([propertyTree(subject, stats)]).concat(["."]);
6229
- }
6230
-
6231
-
6232
- // The property tree for a single subject or anonymous node
6233
- function propertyTree(subject, stats) {
6234
- // print('Proprty tree for '+subject);
6235
- var results = []
6236
- var lastPred = null;
6237
- var sts = stats.subjects[this.toStr(subject)]; // relevant statements
6238
- if (typeof sts == 'undefined') {
6239
- throw('Cant find statements for '+subject);
6240
- }
6241
- sts.sort();
6242
- var objects = [];
6243
- for (var i=0; i<sts.length; i++) {
6244
- var st = sts[i];
6245
- if (st.predicate.uri == lastPred) {
6246
- objects.push(',');
6247
- } else {
6248
- if (lastPred) {
6249
- results=results.concat([objects]).concat([';']);
6250
- objects = [];
6251
- }
6252
- results.push(predMap[st.predicate.uri] ?
6253
- predMap[st.predicate.uri] : termToN3(st.predicate, stats));
6254
- }
6255
- lastPred = st.predicate.uri;
6256
- objects.push(objectTree(st.object, stats));
6257
- }
6258
- results=results.concat([objects]);
6259
- return results;
6260
- }
6261
- propertyTree = propertyTree.bind(this);
6262
-
6263
- function objectTree(obj, stats, force) {
6264
- if (obj.termType == 'bnode' &&
6265
- stats.subjects[this.toStr(obj)] && // and there are statements
6266
- (force || stats.rootsHash[obj.toNT()] == undefined)) // and not a root
6267
- return ['['].concat(propertyTree(obj, stats)).concat([']']);
6268
- return termToN3(obj, stats);
6269
- }
6270
- objectTree = objectTree.bind(this);
6271
-
6272
- function termToN3(expr, stats) {
6273
- switch(expr.termType) {
6274
-
6275
- case 'formula':
6276
- var res = ['{'];
6277
- res = res.concat(statementListToTree(expr.statements));
6278
- return res.concat(['}']);
6279
-
6280
- case 'collection':
6281
- var res = ['('];
6282
- for (i=0; i<expr.elements.length; i++) {
6283
- res.push( [ objectTree(expr.elements[i], stats) ]);
6284
- }
6285
- res.push(')');
6286
- return res;
6287
-
6288
- default:
6289
- return this.atomicTermToN3(expr);
6290
- }
6291
- }
6292
- __Serializer.prototype.termToN3 = termToN3;
6293
- termToN3 = termToN3.bind(this);
6294
-
6295
- function prefixDirectives() {
6296
- var str = '';
6297
- if (this.defaultNamespace)
6298
- str += '@prefix : <'+this.defaultNamespace+'>.\n';
6299
- for (var ns in namespaceCounts) {
6300
- if (!namespaceCounts.hasOwnProperty(ns)) continue;
6301
- str += '@prefix ' + this.prefixes[ns] + ': <'+ns+'>.\n';
6302
- }
6303
- return str + '\n';
6304
- }
6305
- prefixDirectives = prefixDirectives.bind(this);
6306
-
6307
- // Body of statementsToN3:
6308
-
6309
- var tree = statementListToTree(sts);
6310
- return prefixDirectives() + treeToString(tree, -1);
6311
-
6312
- }
6313
-
6314
-
6315
- ////////////////////////////////////////////// Atomic Terms
6316
-
6317
- // Deal with term level things and nesting with no bnode structure
6318
-
6319
-
6320
- __Serializer.prototype.atomicTermToN3 = function atomicTermToN3(expr, stats) {
6321
- switch(expr.termType) {
6322
- case 'bnode':
6323
- case 'variable': return expr.toNT();
6324
- case 'literal':
6325
- if (expr.datatype) {
6326
- switch (expr.datatype.uri) {
6327
- case 'http://www.w3.org/2001/XMLSchema#integer':
6328
- return expr.value.toString();
6329
-
6330
- //case 'http://www.w3.org/2001/XMLSchema#double': // Must force use of 'e'
6331
-
6332
- case 'http://www.w3.org/2001/XMLSchema#boolean':
6333
- return expr.value? 'true' : 'false';
6334
- }
6335
- }
6336
- var str = this.stringToN3(expr.value);
6337
- if (expr.lang) str+= '@' + expr.lang;
6338
- if (expr.datatype) str+= '^^' + this.termToN3(expr.datatype, stats);
6339
- return str;
6340
- case 'symbol':
6341
- return this.symbolToN3(expr);
6342
- default:
6343
- throw "Internal: atomicTermToN3 cannot handle "+expr+" of termType+"+expr.termType
6344
- return ''+expr;
6345
- }
6346
- };
6347
-
6348
- // stringToN3: String escaping for N3
6349
-
6350
- __Serializer.prototype.forbidden1 = new RegExp(/[\\"\b\f\r\v\t\n\u0080-\uffff]/gm);
6351
- __Serializer.prototype.forbidden3 = new RegExp(/[\\"\b\f\r\v\u0080-\uffff]/gm);
6352
- __Serializer.prototype.stringToN3 = function stringToN3(str, flags) {
6353
- if (!flags) flags = "e";
6354
- var res = '', i=0, j=0;
6355
- var delim;
6356
- var forbidden;
6357
- if (str.length > 20 // Long enough to make sense
6358
- && str.slice(-1) != '"' // corner case'
6359
- && flags.indexOf('n') <0 // Force single line
6360
- && (str.indexOf('\n') >0 || str.indexOf('"') > 0)) {
6361
- delim = '"""';
6362
- forbidden = __Serializer.prototype.forbidden3;
6363
- } else {
6364
- delim = '"';
6365
- forbidden = __Serializer.prototype.forbidden1;
6366
- }
6367
- for(i=0; i<str.length;) {
6368
- forbidden.lastIndex = 0;
6369
- var m = forbidden.exec(str.slice(i));
6370
- if (m == null) break;
6371
- j = i + forbidden.lastIndex -1;
6372
- res += str.slice(i,j);
6373
- var ch = str[j];
6374
- if (ch=='"' && delim == '"""' && str.slice(j,j+3) != '"""') {
6375
- res += ch;
6376
-
6377
-
6378
-
6379
- } else {
6380
-
6381
- var k = '\b\f\r\t\v\n\\"'.indexOf(ch); // No escaping of bell (7)?
6382
- if (k >= 0) {
6383
- res += "\\" + 'bfrtvn\\"'[k];
6384
- } else {
6385
- if (flags.indexOf('e')>=0) {
6386
- res += '\\u' + ('000'+
6387
- ch.charCodeAt(0).toString(16).toLowerCase()).slice(-4)
6388
- } else { // no 'e' flag
6389
- res += ch;
6390
-
6391
- }
6392
- }
6393
- }
6394
- i = j+1;
6395
- }
6396
- return delim + res + str.slice(i) + delim
6397
- }
6398
-
6399
-
6400
-
6401
- // A single symbol, either in <> or namespace notation
6402
-
6403
-
6404
- __Serializer.prototype.symbolToN3 = function symbolToN3(x) { // c.f. symbolString() in notation3.py
6405
- var uri = x.uri;
6406
- var j = uri.indexOf('#');
6407
- if (j<0 && this.flags.indexOf('/') < 0) {
6408
- j = uri.lastIndexOf('/');
6409
- }
6410
- if (j >= 0 && this.flags.indexOf('p') < 0) { // Can split at namespace
6411
- var canSplit = true;
6412
- for (var k=j+1; k<uri.length; k++) {
6413
- if (__Serializer.prototype._notNameChars.indexOf(uri[k]) >=0) {
6414
- canSplit = false; break;
6415
- }
6416
- }
6417
- if (canSplit) {
6418
- var localid = uri.slice(j+1);
6419
- var namesp = uri.slice(0,j+1);
6420
- if (this.defaultNamespace && this.defaultNamespace == namesp
6421
- && this.flags.indexOf('d') < 0) {// d -> suppress default
6422
- if (this.flags.indexOf('k') >= 0 &&
6423
- this.keyords.indexOf(localid) <0)
6424
- return localid;
6425
- return ':' + localid;
6426
- }
6427
- var prefix = this.prefixes[namesp];
6428
- if (prefix) {
6429
- //namespaceCounts[namesp] = true;
6430
- return prefix + ':' + localid;
6431
- }
6432
- if (uri.slice(0, j) == this.base)
6433
- return '<#' + localid + '>';
6434
- // Fall though if can't do qname
6435
- }
6436
- }
6437
- if (this.flags.indexOf('r') < 0 && this.base)
6438
- uri = $rdf.Util.uri.refTo(this.base, uri);
6439
- else if (this.flags.indexOf('u') >= 0)
6440
- uri = backslashUify(uri);
6441
- else uri = hexify(uri);
6442
- return '<'+uri+'>';
6443
- }
6444
-
6445
-
6446
- // String ecaping utilities
6447
-
6448
-
6449
- function hexify(str) { // also used in parser
6450
- return encodeURI(str);
6451
- }
6452
-
6453
-
6454
- function backslashUify(str) {
6455
- var res = '', k;
6456
- for (var i=0; i<str.length; i++) {
6457
- k = str.charCodeAt(i);
6458
- if (k>65535)
6459
- res += '\\U' + ('00000000'+k.toString(16)).slice(-8); // convert to upper?
6460
- else if (k>126)
6461
- res += '\\u' + ('0000'+k.toString(16)).slice(-4);
6462
- else
6463
- res += str[i];
6464
- }
6465
- return res;
6466
- }
6467
-
6468
-
6469
- ///////////////////////////// Quad store serialization
6470
-
6471
-
6472
- // @para. write - a function taking a single string to be output
6473
- //
6474
- __Serializer.prototype.writeStore = function(write) {
6475
-
6476
- var kb = this.store;
6477
- var fetcher = kb.fetcher;
6478
- var session = fetcher && fetcher.appNode;
6479
-
6480
- // Everything we know from experience just write out.
6481
- if (session) write(this.statementsToN3(kb.statementsMatching(
6482
- undefined, undefined, undefined, session)));
6483
-
6484
- var sources = this.store.index[3];
6485
- for (s in sources) { // -> assume we can use -> as short for log:semantics
6486
- var source = kb.fromNT(s);
6487
- if (session && source.sameTerm(session)) continue;
6488
- write('\n'+ this.atomicTermToN3(source)+' -> { '+ this.statementsToN3(kb.statementsMatching(
6489
- undefined, undefined, undefined, source)) + ' }.\n');
6490
- }
6491
- }
6492
-
6493
-
6494
-
6495
-
6496
-
6497
- //////////////////////////////////////////////// XML serialization
6498
-
6499
- __Serializer.prototype.statementsToXML = function(sts) {
6500
- var indent = 4;
6501
- var width = 80;
6502
-
6503
- var namespaceCounts = []; // which have been used
6504
- namespaceCounts['http://www.w3.org/1999/02/22-rdf-syntax-ns#'] = true;
6505
-
6506
- var liPrefix = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_'; //prefix for ordered list items
6507
-
6508
- ////////////////////////// Arrange the bits of XML text
6509
-
6510
- var spaces=function(n) {
6511
- var s='';
6512
- for(var i=0; i<n; i++) s+=' ';
6513
- return s
6514
- }
6515
-
6516
- var XMLtreeToLine = function(tree) {
6517
- var str = '';
6518
- for (var i=0; i<tree.length; i++) {
6519
- var branch = tree[i];
6520
- var s2 = (typeof branch == 'string') ? branch : XMLtreeToLine(branch);
6521
- str += s2;
6522
- }
6523
- return str;
6524
- }
6525
-
6526
- // Convert a nested tree of lists and strings to a string
6527
- var XMLtreeToString = function(tree, level) {
6528
- var str = '';
6529
- var lastLength = 100000;
6530
- if (!level) level = 0;
6531
- for (var i=0; i<tree.length; i++) {
6532
- var branch = tree[i];
6533
- if (typeof branch != 'string') {
6534
- var substr = XMLtreeToString(branch, level +1);
6535
- if (
6536
- substr.length < 10*(width-indent*level)
6537
- && substr.indexOf('"""') < 0) {// Don't mess up multiline strings
6538
- var line = XMLtreeToLine(branch);
6539
- if (line.length < (width-indent*level)) {
6540
- branch = ' '+line; // @@ Hack: treat as string below
6541
- substr = ''
6542
- }
6543
- }
6544
- if (substr) lastLength = 10000;
6545
- str += substr;
6546
- }
6547
- if (typeof branch == 'string') {
6548
- if (lastLength < (indent*level+4)) { // continue
6549
- str = str.slice(0,-1) + ' ' + branch + '\n';
6550
- lastLength += branch.length + 1;
6551
- } else {
6552
- var line = spaces(indent*level) +branch;
6553
- str += line +'\n';
6554
- lastLength = line.length;
6555
- }
6556
-
6557
- } else { // not string
6558
- }
6559
- }
6560
- return str;
6561
- };
6562
-
6563
- function statementListToXMLTree(statements) {
6564
- this.suggestPrefix('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
6565
- var stats = this.rootSubjects(statements);
6566
- var roots = stats.roots;
6567
- var results = []
6568
- for (var i=0; i<roots.length; i++) {
6569
- root = roots[i];
6570
- results.push(subjectXMLTree(root, stats))
6571
- }
6572
- return results;
6573
- }
6574
- statementListToXMLTree = statementListToXMLTree.bind(this);
6575
-
6576
- function escapeForXML(str) {
6577
- if (typeof str == 'undefined') return '@@@undefined@@@@';
6578
- return str.replace(/[&<"]/g, function(m) {
6579
- switch(m[0]) {
6580
- case '&':
6581
- return '&amp;';
6582
- case '<':
6583
- return '&lt;';
6584
- case '"':
6585
- return '&quot;';
6586
- }
6587
- });
6588
- }
6589
-
6590
- function relURI(term) {
6591
- return escapeForXML((this.base) ? $rdf.Util.uri.refTo(this.base, term.uri) : term.uri);
6592
- }
6593
- relURI = relURI.bind(this);
6594
-
6595
- // The tree for a subject
6596
- function subjectXMLTree(subject, stats) {
6597
- var results = [];
6598
- var type, t, st, pred;
6599
- var sts = stats.subjects[this.toStr(subject)]; // relevant statements
6600
- if (typeof sts == 'undefined') {
6601
- throw('Cant find statements for '+subject);
6602
- }
6603
-
6604
-
6605
- // Sort only on the predicate, leave the order at object
6606
- // level undisturbed. This leaves multilingual content in
6607
- // the order of entry (for partner literals), which helps
6608
- // readability.
6609
- //
6610
- // For the predicate sort, we attempt to split the uri
6611
- // as a hint to the sequence
6612
- sts.sort(function(a,b) {
6613
- var ap = a.predicate.uri;
6614
- var bp = b.predicate.uri;
6615
- if(ap.substring(0,liPrefix.length) == liPrefix || bp.substring(0,liPrefix.length) == liPrefix) { //we're only interested in sorting list items
6616
- return ap.localeCompare(bp);
6617
- }
6618
-
6619
- var as = ap.substring(liPrefix.length);
6620
- var bs = bp.substring(liPrefix.length);
6621
- var an = parseInt(as);
6622
- var bn = parseInt(bs);
6623
- if(isNaN(an) || isNaN(bn) ||
6624
- an != as || bn != bs) { //we only care about integers
6625
- return ap.localeCompare(bp);
6626
- }
6627
-
6628
- return an - bn;
6629
- });
6630
-
6631
-
6632
- for (var i=0; i<sts.length; i++) {
6633
- st = sts[i];
6634
- // look for a type
6635
- if(st.predicate.uri == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' && !type && st.object.termType == "symbol") {
6636
- type = st.object;
6637
- continue; //don't include it as a child element
6638
- }
6639
-
6640
- // see whether predicate can be replaced with "li"
6641
- pred = st.predicate;
6642
- if(pred.uri.substr(0, liPrefix.length) == liPrefix) {
6643
- var number = pred.uri.substr(liPrefix.length);
6644
- // make sure these are actually numeric list items
6645
- var intNumber = parseInt(number);
6646
- if(number == intNumber.toString()) {
6647
- // was numeric; don't need to worry about ordering since we've already
6648
- // sorted the statements
6649
- pred = new $rdf.Symbol('http://www.w3.org/1999/02/22-rdf-syntax-ns#li');
6650
- }
6651
- }
6652
-
6653
- t = qname(pred);
6654
- switch (st.object.termType) {
6655
- case 'bnode':
6656
- if(stats.incoming[st.object].length == 1) { //there should always be something in the incoming array for a bnode
6657
- results = results.concat(['<'+ t +'>',
6658
- subjectXMLTree(st.object, stats),
6659
- '</'+ t +'>']);
6660
- } else {
6661
- results = results.concat(['<'+ t +' rdf:nodeID="'
6662
- +st.object.toNT().slice(2)+'"/>']);
6663
- }
6664
- break;
6665
- case 'symbol':
6666
- results = results.concat(['<'+ t +' rdf:resource="'
6667
- + relURI(st.object)+'"/>']);
6668
- break;
6669
- case 'literal':
6670
- results = results.concat(['<'+ t
6671
- + (st.object.dt ? ' rdf:datatype="'+escapeForXML(st.object.dt.uri)+'"' : '')
6672
- + (st.object.lang ? ' xml:lang="'+st.object.lang+'"' : '')
6673
- + '>' + escapeForXML(st.object.value)
6674
- + '</'+ t +'>']);
6675
- break;
6676
- case 'collection':
6677
- results = results.concat(['<'+ t +' rdf:parseType="Collection">',
6678
- collectionXMLTree(st.object, stats),
6679
- '</'+ t +'>']);
6680
- break;
6681
- default:
6682
- throw "Can't serialize object of type "+st.object.termType +" into XML";
6683
- } // switch
6684
- }
6685
-
6686
- var tag = type ? qname(type) : 'rdf:Description';
6687
-
6688
- var attrs = '';
6689
- if (subject.termType == 'bnode') {
6690
- if(!stats.incoming[subject] || stats.incoming[subject].length != 1) { // not an anonymous bnode
6691
- attrs = ' rdf:nodeID="'+subject.toNT().slice(2)+'"';
6692
- }
6693
- } else {
6694
- attrs = ' rdf:about="'+ relURI(subject)+'"';
6695
- }
6696
-
6697
- return [ '<' + tag + attrs + '>' ].concat([results]).concat(["</"+ tag +">"]);
6698
- }
6699
-
6700
- subjectXMLTree = subjectXMLTree.bind(this);
6701
-
6702
- function collectionXMLTree(subject, stats) {
6703
- var res = []
6704
- for (var i=0; i< subject.elements.length; i++) {
6705
- res.push(subjectXMLTree(subject.elements[i], stats));
6706
- }
6707
- return res;
6708
- }
6709
-
6710
- // The property tree for a single subject or anonymos node
6711
- function propertyXMLTree(subject, stats) {
6712
- var results = []
6713
- var sts = stats.subjects[this.toStr(subject)]; // relevant statements
6714
- if (sts == undefined) return results; // No relevant statements
6715
- sts.sort();
6716
- for (var i=0; i<sts.length; i++) {
6717
- var st = sts[i];
6718
- switch (st.object.termType) {
6719
- case 'bnode':
6720
- if(stats.rootsHash[st.object.toNT()]) { // This bnode has been done as a root -- no content here @@ what bout first time
6721
- results = results.concat(['<'+qname(st.predicate)+' rdf:nodeID="'+st.object.toNT().slice(2)+'">',
6722
- '</'+qname(st.predicate)+'>']);
6723
- } else {
6724
- results = results.concat(['<'+qname(st.predicate)+' rdf:parseType="Resource">',
6725
- propertyXMLTree(st.object, stats),
6726
- '</'+qname(st.predicate)+'>']);
6727
- }
6728
- break;
6729
- case 'symbol':
6730
- results = results.concat(['<'+qname(st.predicate)+' rdf:resource="'
6731
- + relURI(st.object)+'"/>']);
6732
- break;
6733
- case 'literal':
6734
- results = results.concat(['<'+qname(st.predicate)
6735
- + (st.object.datatype ? ' rdf:datatype="'+escapeForXML(st.object.datatype.uri)+'"' : '')
6736
- + (st.object.lang ? ' xml:lang="'+st.object.lang+'"' : '')
6737
- + '>' + escapeForXML(st.object.value)
6738
- + '</'+qname(st.predicate)+'>']);
6739
- break;
6740
- case 'collection':
6741
- results = results.concat(['<'+qname(st.predicate)+' rdf:parseType="Collection">',
6742
- collectionXMLTree(st.object, stats),
6743
- '</'+qname(st.predicate)+'>']);
6744
- break;
6745
- default:
6746
- throw "Can't serialize object of type "+st.object.termType +" into XML";
6747
-
6748
- } // switch
6749
- }
6750
- return results;
6751
- }
6752
- propertyXMLTree = propertyXMLTree.bind(this);
6753
-
6754
- function qname(term) {
6755
- var uri = term.uri;
6756
-
6757
- var j = uri.indexOf('#');
6758
- if (j<0 && this.flags.indexOf('/') < 0) {
6759
- j = uri.lastIndexOf('/');
6760
- }
6761
- if (j < 0) throw ("Cannot make qname out of <"+uri+">")
6762
-
6763
- var canSplit = true;
6764
- for (var k=j+1; k<uri.length; k++) {
6765
- if (__Serializer.prototype._notNameChars.indexOf(uri[k]) >=0) {
6766
- throw ('Invalid character "'+uri[k] +'" cannot be in XML qname for URI: '+uri);
6767
- }
6768
- }
6769
- var localid = uri.slice(j+1);
6770
- var namesp = uri.slice(0,j+1);
6771
- if (this.defaultNamespace && this.defaultNamespace == namesp
6772
- && this.flags.indexOf('d') < 0) {// d -> suppress default
6773
- return localid;
6774
- }
6775
- var prefix = this.prefixes[namesp];
6776
- if (!prefix) prefix = this.makeUpPrefix(namesp);
6777
- namespaceCounts[namesp] = true;
6778
- return prefix + ':' + localid;
6779
- // throw ('No prefix for namespace "'+namesp +'" for XML qname for '+uri+', namespaces: '+sz.prefixes+' sz='+sz);
6780
- }
6781
- qname = qname.bind(this);
6782
-
6783
- // Body of toXML:
6784
-
6785
- var tree = statementListToXMLTree(sts);
6786
- var str = '<rdf:RDF';
6787
- if (this.defaultNamespace)
6788
- str += ' xmlns="'+escapeForXML(this.defaultNamespace)+'"';
6789
- for (var ns in namespaceCounts) {
6790
- if (!namespaceCounts.hasOwnProperty(ns)) continue;
6791
- str += '\n xmlns:' + this.prefixes[ns] + '="'+escapeForXML(ns)+'"';
6792
- }
6793
- str += '>';
6794
-
6795
- var tree2 = [str, tree, '</rdf:RDF>']; //@@ namespace declrations
6796
- return XMLtreeToString(tree2, -1);
6797
-
6798
-
6799
- } // End @@ body
6800
-
6801
- var Serializer = function( store ) {return new __Serializer( store )};
6802
- return Serializer;
6803
-
6804
- }();
5792
+ /* Serialization of RDF Graphs
5793
+ **
5794
+ ** Tim Berners-Lee 2006
5795
+ ** This is or was http://dig.csail.mit.edu/2005/ajar/ajaw/js/rdf/serialize.js
5796
+ **
5797
+ ** Bug: can't serialize http://data.semanticweb.org/person/abraham-bernstein/rdf
5798
+ ** in XML (from mhausenblas)
5799
+ */
5800
+
5801
+ // @@@ Check the whole toStr thing tosee whetehr it still makes sense -- tbl
5802
+ //
5803
+ $rdf.Serializer = function() {
5804
+
5805
+ var __Serializer = function( store ){
5806
+ this.flags = "";
5807
+ this.base = null;
5808
+ this.prefixes = [];
5809
+ this.namespacesUsed = [];
5810
+ this.keywords = ['a']; // The only one we generate at the moment
5811
+ this.prefixchars = "abcdefghijklmnopqustuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
5812
+ this.incoming = null; // Array not calculated yet
5813
+ this.formulas = []; // remebering original formulae from hashes
5814
+ this.store = store;
5815
+
5816
+ /* pass */
5817
+ }
5818
+
5819
+ __Serializer.prototype.setBase = function(base)
5820
+ { this.base = base };
5821
+
5822
+ __Serializer.prototype.setFlags = function(flags)
5823
+ { this.flags = flags?flags: '' };
5824
+
5825
+
5826
+ __Serializer.prototype.toStr = function(x) {
5827
+ var s = x.toNT();
5828
+ if (x.termType == 'formula') {
5829
+ this.formulas[s] = x; // remember as reverse does not work
5830
+ }
5831
+ return s;
5832
+ };
5833
+
5834
+ __Serializer.prototype.fromStr = function(s) {
5835
+ if (s[0] == '{') {
5836
+ var x = this.formulas[s];
5837
+ if (!x) alert('No formula object for '+s)
5838
+ return x;
5839
+ }
5840
+ return this.store.fromNT(s);
5841
+ };
5842
+
5843
+
5844
+
5845
+
5846
+
5847
+ /* Accumulate Namespaces
5848
+ **
5849
+ ** These are only hints. If two overlap, only one gets used
5850
+ ** There is therefore no guarantee in general.
5851
+ */
5852
+
5853
+ __Serializer.prototype.suggestPrefix = function(prefix, uri) {
5854
+ if (prefix.slice(0,7) === 'default') return; // Try to weed these out
5855
+ if (prefix.slice(0,2) === 'ns') return; // From others inferior algos
5856
+ this.prefixes[uri] = prefix;
5857
+ }
5858
+
5859
+ // Takes a namespace -> prefix map
5860
+ __Serializer.prototype.suggestNamespaces = function(namespaces) {
5861
+ for (var px in namespaces) {
5862
+ this.prefixes[namespaces[px]] = px;
5863
+ }
5864
+ }
5865
+
5866
+ // Make up an unused prefix for a random namespace
5867
+ __Serializer.prototype.makeUpPrefix = function(uri) {
5868
+ var p = uri;
5869
+ var namespaces = [];
5870
+ var pok;
5871
+
5872
+ function canUse(pp) {
5873
+ if (namespaces[pp]) return false; // already used
5874
+ this.prefixes[uri] = pp;
5875
+ pok = pp;
5876
+ return true
5877
+ }
5878
+ canUse = canUse.bind(this);
5879
+ for (var ns in this.prefixes) {
5880
+ namespaces[this.prefixes[ns]] = ns; // reverse index
5881
+ }
5882
+ if ('#/'.indexOf(p[p.length-1]) >= 0) p = p.slice(0, -1);
5883
+ var slash = p.lastIndexOf('/');
5884
+ if (slash >= 0) p = p.slice(slash+1);
5885
+ var i = 0;
5886
+ while (i < p.length)
5887
+ if (this.prefixchars.indexOf(p[i])) i++; else break;
5888
+ p = p.slice(0,i);
5889
+ if (p.length < 6 && canUse(p)) return pok; // exact i sbest
5890
+ if (canUse(p.slice(0,3))) return pok;
5891
+ if (canUse(p.slice(0,2))) return pok;
5892
+ if (canUse(p.slice(0,4))) return pok;
5893
+ if (canUse(p.slice(0,1))) return pok;
5894
+ if (canUse(p.slice(0,5))) return pok;
5895
+ for (var i=0;; i++) if (canUse(p.slice(0,3)+i)) return pok;
5896
+ }
5897
+
5898
+
5899
+
5900
+ // Todo:
5901
+ // - Sort the statements by subject, pred, object
5902
+ // - do stuff about the docu first and then (or first) about its primary topic.
5903
+
5904
+ __Serializer.prototype.rootSubjects = function(sts) {
5905
+ var incoming = {};
5906
+ var subjects = {};
5907
+ var allBnodes = {};
5908
+
5909
+ /* This scan is to find out which nodes will have to be the roots of trees
5910
+ ** in the serialized form. This will be any symbols, and any bnodes
5911
+ ** which hve more or less than one incoming arc, and any bnodes which have
5912
+ ** one incoming arc but it is an uninterrupted loop of such nodes back to itself.
5913
+ ** This should be kept linear time with repect to the number of statements.
5914
+ ** Note it does not use any indexing of the store.
5915
+ */
5916
+
5917
+
5918
+ // $rdf.log.debug('serialize.js Find bnodes with only one incoming arc\n')
5919
+ for (var i = 0; i<sts.length; i++) {
5920
+ var st = sts[i];
5921
+ [ st.subject, st.predicate, st.object].map(function(y){
5922
+ if (y.termType =='bnode'){allBnodes[y.toNT()] = true}});
5923
+ var x = sts[i].object;
5924
+ if (!incoming.hasOwnProperty(x)) incoming[x] = [];
5925
+ incoming[x].push(st.subject) // List of things which will cause this to be printed
5926
+ var ss = subjects[this.toStr(st.subject)]; // Statements with this as subject
5927
+ if (!ss) ss = [];
5928
+ ss.push(st);
5929
+ subjects[this.toStr(st.subject)] = ss; // Make hash. @@ too slow for formula?
5930
+ // $rdf.log.debug(' sz potential subject: '+sts[i].subject)
5931
+ }
5932
+
5933
+ var roots = [];
5934
+ for (var xNT in subjects) {
5935
+ if (!subjects.hasOwnProperty(xNT)) continue;
5936
+ var x = this.fromStr(xNT);
5937
+ if ((x.termType != 'bnode') || !incoming[x] || (incoming[x].length != 1)){
5938
+ roots.push(x);
5939
+ //$rdf.log.debug(' sz actual subject -: ' + x)
5940
+ continue;
5941
+ }
5942
+ }
5943
+ this.incoming = incoming; // Keep for serializing @@ Bug for nested formulas
5944
+
5945
+ //////////// New bit for CONNECTED bnode loops:frootshash
5946
+
5947
+ // This scans to see whether the serialization is gpoing to lead to a bnode loop
5948
+ // and at the same time accumulates a list of all bnodes mentioned.
5949
+ // This is in fact a cut down N3 serialization
5950
+ /*
5951
+ // $rdf.log.debug('serialize.js Looking for connected bnode loops\n')
5952
+ for (var i=0; i<sts.length; i++) { // @@TBL
5953
+ // dump('\t'+sts[i]+'\n');
5954
+ }
5955
+ var doneBnodesNT = {};
5956
+ function dummyPropertyTree(subject, subjects, rootsHash) {
5957
+ // dump('dummyPropertyTree('+subject+'...)\n');
5958
+ var sts = subjects[sz.toStr(subject)]; // relevant statements
5959
+ for (var i=0; i<sts.length; i++) {
5960
+ dummyObjectTree(sts[i].object, subjects, rootsHash);
5961
+ }
5962
+ }
5963
+
5964
+ // Convert a set of statements into a nested tree of lists and strings
5965
+ // @param force, "we know this is a root, do it anyway. It isn't a loop."
5966
+ function dummyObjectTree(obj, subjects, rootsHash, force) {
5967
+ // dump('dummyObjectTree('+obj+'...)\n');
5968
+ if (obj.termType == 'bnode' && (subjects[sz.toStr(obj)] &&
5969
+ (force || (rootsHash[obj.toNT()] == undefined )))) {// and there are statements
5970
+ if (doneBnodesNT[obj.toNT()]) { // Ah-ha! a loop
5971
+ throw "Serializer: Should be no loops "+obj;
5972
+ }
5973
+ doneBnodesNT[obj.toNT()] = true;
5974
+ return dummyPropertyTree(obj, subjects, rootsHash);
5975
+ }
5976
+ return dummyTermToN3(obj, subjects, rootsHash);
5977
+ }
5978
+
5979
+ // Scan for bnodes nested inside lists too
5980
+ function dummyTermToN3(expr, subjects, rootsHash) {
5981
+ if (expr.termType == 'bnode') doneBnodesNT[expr.toNT()] = true;
5982
+ // $rdf.log.debug('serialize: seen '+expr);
5983
+ if (expr.termType == 'collection') {
5984
+ for (i=0; i<expr.elements.length; i++) {
5985
+ if (expr.elements[i].termType == 'bnode')
5986
+ dummyObjectTree(expr.elements[i], subjects, rootsHash);
5987
+ }
5988
+ return;
5989
+ }
5990
+ }
5991
+
5992
+ // The tree for a subject
5993
+ function dummySubjectTree(subject, subjects, rootsHash) {
5994
+ // dump('dummySubjectTree('+subject+'...)\n');
5995
+ if (subject.termType == 'bnode' && !incoming[subject])
5996
+ return dummyObjectTree(subject, subjects, rootsHash, true); // Anonymous bnode subject
5997
+ dummyTermToN3(subject, subjects, rootsHash);
5998
+ dummyPropertyTree(subject, subjects, rootsHash);
5999
+ }
6000
+ */
6001
+ // Now do the scan using existing roots
6002
+ // $rdf.log.debug('serialize.js Dummy serialize to check for missing nodes')
6003
+ var rootsHash = {};
6004
+ for (var i = 0; i< roots.length; i++) rootsHash[roots[i].toNT()] = true;
6005
+ /*
6006
+ for (var i=0; i<roots.length; i++) {
6007
+ var root = roots[i];
6008
+ dummySubjectTree(root, subjects, rootsHash);
6009
+ }
6010
+ // dump('Looking for mising bnodes...\n')
6011
+
6012
+ // Now in new roots for anythig not acccounted for
6013
+ // Now we check for any bndoes which have not been covered.
6014
+ // Such bnodes must be in isolated rings of pure bnodes.
6015
+ // They each have incoming link of 1.
6016
+
6017
+ // $rdf.log.debug('serialize.js Looking for connected bnode loops\n')
6018
+ for (;;) {
6019
+ var bnt;
6020
+ var found = null;
6021
+ for (bnt in allBnodes) { // @@ Note: not repeatable. No canonicalisation
6022
+ if (doneBnodesNT[bnt]) continue;
6023
+ found = bnt; // Ah-ha! not covered
6024
+ break;
6025
+ }
6026
+ if (found == null) break; // All done - no bnodes left out/
6027
+ // dump('Found isolated bnode:'+found+'\n');
6028
+ doneBnodesNT[bnt] = true;
6029
+ var root = this.store.fromNT(found);
6030
+ roots.push(root); // Add a new root
6031
+ rootsHash[found] = true;
6032
+ // $rdf.log.debug('isolated bnode:'+found+', subjects[found]:'+subjects[found]+'\n');
6033
+ if (subjects[found] == undefined) {
6034
+ for (var i=0; i<sts.length; i++) {
6035
+ // dump('\t'+sts[i]+'\n');
6036
+ }
6037
+ throw "Isolated node should be a subject" +found;
6038
+ }
6039
+ dummySubjectTree(root, subjects, rootsHash); // trace out the ring
6040
+ }
6041
+ // dump('Done bnode adjustments.\n')
6042
+ */
6043
+ return {'roots':roots, 'subjects':subjects,
6044
+ 'rootsHash': rootsHash, 'incoming': incoming};
6045
+ }
6046
+
6047
+ ////////////////////////////////////////////////////////
6048
+
6049
+ __Serializer.prototype.toN3 = function(f) {
6050
+ return this.statementsToN3(f.statements);
6051
+ }
6052
+
6053
+ __Serializer.prototype._notQNameChars = "\t\r\n !\"#$%&'()*.,+/;<=>?@[\\]^`{|}~";
6054
+ __Serializer.prototype._notNameChars =
6055
+ ( __Serializer.prototype._notQNameChars + ":" ) ;
6056
+
6057
+
6058
+ __Serializer.prototype.statementsToN3 = function(sts) {
6059
+ var indent = 4;
6060
+ var width = 80;
6061
+
6062
+ var predMap = {
6063
+ 'http://www.w3.org/2002/07/owl#sameAs': '=',
6064
+ 'http://www.w3.org/2000/10/swap/log#implies': '=>',
6065
+ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type': 'a'
6066
+ }
6067
+
6068
+
6069
+
6070
+
6071
+ ////////////////////////// Arrange the bits of text
6072
+
6073
+ var spaces=function(n) {
6074
+ var s='';
6075
+ for(var i=0; i<n; i++) s+=' ';
6076
+ return s
6077
+ }
6078
+
6079
+ var treeToLine = function(tree) {
6080
+ var str = '';
6081
+ for (var i=0; i<tree.length; i++) {
6082
+ var branch = tree[i];
6083
+ var s2 = (typeof branch == 'string') ? branch : treeToLine(branch);
6084
+ if (i!=0 && s2 != ',' && s2 != ';' && s2 != '.') str += ' ';
6085
+ str += s2;
6086
+ }
6087
+ return str;
6088
+ }
6089
+
6090
+ // Convert a nested tree of lists and strings to a string
6091
+ var treeToString = function(tree, level) {
6092
+ var str = '';
6093
+ var lastLength = 100000;
6094
+ if (!level) level = 0;
6095
+ for (var i=0; i<tree.length; i++) {
6096
+ var branch = tree[i];
6097
+ if (typeof branch != 'string') {
6098
+ var substr = treeToString(branch, level +1);
6099
+ if (
6100
+ substr.length < 10*(width-indent*level)
6101
+ && substr.indexOf('"""') < 0) {// Don't mess up multiline strings
6102
+ var line = treeToLine(branch);
6103
+ if (line.length < (width-indent*level)) {
6104
+ branch = ' '+line; // @@ Hack: treat as string below
6105
+ substr = ''
6106
+ }
6107
+ }
6108
+ if (substr) lastLength = 10000;
6109
+ str += substr;
6110
+ }
6111
+ if (typeof branch == 'string') {
6112
+ if (branch.length == '1' && str.slice(-1) == '\n') {
6113
+ if (",.;".indexOf(branch) >=0) {
6114
+ str = str.slice(0,-1) + branch + '\n'; // slip punct'n on end
6115
+ lastLength += 1;
6116
+ continue;
6117
+ } else if ("])}".indexOf(branch) >=0) {
6118
+ str = str.slice(0,-1) + ' ' + branch + '\n';
6119
+ lastLength += 2;
6120
+ continue;
6121
+ }
6122
+ }
6123
+ if (lastLength < (indent*level+4)) { // continue
6124
+ str = str.slice(0,-1) + ' ' + branch + '\n';
6125
+ lastLength += branch.length + 1;
6126
+ } else {
6127
+ var line = spaces(indent*level) +branch;
6128
+ str += line +'\n';
6129
+ lastLength = line.length;
6130
+ }
6131
+
6132
+ } else { // not string
6133
+ }
6134
+ }
6135
+ return str;
6136
+ };
6137
+
6138
+ ////////////////////////////////////////////// Structure for N3
6139
+
6140
+
6141
+ // Convert a set of statements into a nested tree of lists and strings
6142
+ function statementListToTree(statements) {
6143
+ // print('Statement tree for '+statements.length);
6144
+ var res = [];
6145
+ var stats = this.rootSubjects(statements);
6146
+ var roots = stats.roots;
6147
+ var results = []
6148
+ for (var i=0; i<roots.length; i++) {
6149
+ var root = roots[i];
6150
+ results.push(subjectTree(root, stats))
6151
+ }
6152
+ return results;
6153
+ }
6154
+ statementListToTree = statementListToTree.bind(this);
6155
+
6156
+ // The tree for a subject
6157
+ function subjectTree(subject, stats) {
6158
+ if (subject.termType == 'bnode' && !stats.incoming[subject])
6159
+ return objectTree(subject, stats, true).concat(["."]); // Anonymous bnode subject
6160
+ return [ termToN3(subject, stats) ].concat([propertyTree(subject, stats)]).concat(["."]);
6161
+ }
6162
+
6163
+
6164
+ // The property tree for a single subject or anonymous node
6165
+ function propertyTree(subject, stats) {
6166
+ // print('Proprty tree for '+subject);
6167
+ var results = []
6168
+ var lastPred = null;
6169
+ var sts = stats.subjects[this.toStr(subject)]; // relevant statements
6170
+ if (typeof sts == 'undefined') {
6171
+ throw('Cant find statements for '+subject);
6172
+ }
6173
+ sts.sort();
6174
+ var objects = [];
6175
+ for (var i=0; i<sts.length; i++) {
6176
+ var st = sts[i];
6177
+ if (st.predicate.uri == lastPred) {
6178
+ objects.push(',');
6179
+ } else {
6180
+ if (lastPred) {
6181
+ results=results.concat([objects]).concat([';']);
6182
+ objects = [];
6183
+ }
6184
+ results.push(predMap[st.predicate.uri] ?
6185
+ predMap[st.predicate.uri] : termToN3(st.predicate, stats));
6186
+ }
6187
+ lastPred = st.predicate.uri;
6188
+ objects.push(objectTree(st.object, stats));
6189
+ }
6190
+ results=results.concat([objects]);
6191
+ return results;
6192
+ }
6193
+ propertyTree = propertyTree.bind(this);
6194
+
6195
+ function objectTree(obj, stats, force) {
6196
+ if (obj.termType == 'bnode' &&
6197
+ stats.subjects[this.toStr(obj)] && // and there are statements
6198
+ (force || stats.rootsHash[obj.toNT()] == undefined)) // and not a root
6199
+ return ['['].concat(propertyTree(obj, stats)).concat([']']);
6200
+ return termToN3(obj, stats);
6201
+ }
6202
+ objectTree = objectTree.bind(this);
6203
+
6204
+ function termToN3(expr, stats) {
6205
+ switch(expr.termType) {
6206
+
6207
+ case 'formula':
6208
+ var res = ['{'];
6209
+ res = res.concat(statementListToTree(expr.statements));
6210
+ return res.concat(['}']);
6211
+
6212
+ case 'collection':
6213
+ var res = ['('];
6214
+ for (i=0; i<expr.elements.length; i++) {
6215
+ res.push( [ objectTree(expr.elements[i], stats) ]);
6216
+ }
6217
+ res.push(')');
6218
+ return res;
6219
+
6220
+ default:
6221
+ return this.atomicTermToN3(expr);
6222
+ }
6223
+ }
6224
+ __Serializer.prototype.termToN3 = termToN3;
6225
+ termToN3 = termToN3.bind(this);
6226
+
6227
+ function prefixDirectives() {
6228
+ var str = '';
6229
+ if (this.defaultNamespace)
6230
+ str += '@prefix : <'+this.defaultNamespace+'>.\n';
6231
+ for (var ns in this.prefixes) {
6232
+ if (!this.prefixes.hasOwnProperty(ns)) continue;
6233
+ if (!this.namespacesUsed[ns]) continue;
6234
+ str += '@prefix ' + this.prefixes[ns] + ': <'+ns+'>.\n';
6235
+ }
6236
+ return str + '\n';
6237
+ }
6238
+ prefixDirectives = prefixDirectives.bind(this);
6239
+
6240
+ // Body of statementsToN3:
6241
+
6242
+ var tree = statementListToTree(sts);
6243
+ return prefixDirectives() + treeToString(tree, -1);
6244
+
6245
+ }
6246
+
6247
+
6248
+ ////////////////////////////////////////////// Atomic Terms
6249
+
6250
+ // Deal with term level things and nesting with no bnode structure
6251
+
6252
+
6253
+ __Serializer.prototype.atomicTermToN3 = function atomicTermToN3(expr, stats) {
6254
+ switch(expr.termType) {
6255
+ case 'bnode':
6256
+ case 'variable': return expr.toNT();
6257
+ case 'literal':
6258
+ if (expr.datatype) {
6259
+ switch (expr.datatype.uri) {
6260
+ case 'http://www.w3.org/2001/XMLSchema#integer':
6261
+ return expr.value.toString();
6262
+
6263
+ //case 'http://www.w3.org/2001/XMLSchema#double': // Must force use of 'e'
6264
+
6265
+ case 'http://www.w3.org/2001/XMLSchema#boolean':
6266
+ return expr.value? 'true' : 'false';
6267
+ }
6268
+ }
6269
+ var str = this.stringToN3(expr.value);
6270
+ if (expr.lang) str+= '@' + expr.lang;
6271
+ if (expr.datatype) str+= '^^' + this.termToN3(expr.datatype, stats);
6272
+ return str;
6273
+ case 'symbol':
6274
+ return this.symbolToN3(expr);
6275
+ default:
6276
+ throw "Internal: atomicTermToN3 cannot handle "+expr+" of termType+"+expr.termType
6277
+ return ''+expr;
6278
+ }
6279
+ };
6280
+
6281
+ // stringToN3: String escaping for N3
6282
+
6283
+ __Serializer.prototype.forbidden1 = new RegExp(/[\\"\b\f\r\v\t\n\u0080-\uffff]/gm);
6284
+ __Serializer.prototype.forbidden3 = new RegExp(/[\\"\b\f\r\v\u0080-\uffff]/gm);
6285
+ __Serializer.prototype.stringToN3 = function stringToN3(str, flags) {
6286
+ if (!flags) flags = "e";
6287
+ var res = '', i=0, j=0;
6288
+ var delim;
6289
+ var forbidden;
6290
+ if (str.length > 20 // Long enough to make sense
6291
+ && str.slice(-1) != '"' // corner case'
6292
+ && flags.indexOf('n') <0 // Force single line
6293
+ && (str.indexOf('\n') >0 || str.indexOf('"') > 0)) {
6294
+ delim = '"""';
6295
+ forbidden = __Serializer.prototype.forbidden3;
6296
+ } else {
6297
+ delim = '"';
6298
+ forbidden = __Serializer.prototype.forbidden1;
6299
+ }
6300
+ for(i=0; i<str.length;) {
6301
+ forbidden.lastIndex = 0;
6302
+ var m = forbidden.exec(str.slice(i));
6303
+ if (m == null) break;
6304
+ j = i + forbidden.lastIndex -1;
6305
+ res += str.slice(i,j);
6306
+ var ch = str[j];
6307
+ if (ch=='"' && delim == '"""' && str.slice(j,j+3) != '"""') {
6308
+ res += ch;
6309
+
6310
+
6311
+
6312
+ } else {
6313
+
6314
+ var k = '\b\f\r\t\v\n\\"'.indexOf(ch); // No escaping of bell (7)?
6315
+ if (k >= 0) {
6316
+ res += "\\" + 'bfrtvn\\"'[k];
6317
+ } else {
6318
+ if (flags.indexOf('e')>=0) {
6319
+ res += '\\u' + ('000'+
6320
+ ch.charCodeAt(0).toString(16).toLowerCase()).slice(-4)
6321
+ } else { // no 'e' flag
6322
+ res += ch;
6323
+
6324
+ }
6325
+ }
6326
+ }
6327
+ i = j+1;
6328
+ }
6329
+ return delim + res + str.slice(i) + delim
6330
+ }
6331
+
6332
+
6333
+
6334
+ // A single symbol, either in <> or namespace notation
6335
+
6336
+
6337
+ __Serializer.prototype.symbolToN3 = function symbolToN3(x) { // c.f. symbolString() in notation3.py
6338
+ var uri = x.uri;
6339
+ var j = uri.indexOf('#');
6340
+ if (j<0 && this.flags.indexOf('/') < 0) {
6341
+ j = uri.lastIndexOf('/');
6342
+ }
6343
+ if (j >= 0 && this.flags.indexOf('p') < 0) { // Can split at namespace
6344
+ var canSplit = true;
6345
+ for (var k=j+1; k<uri.length; k++) {
6346
+ if (__Serializer.prototype._notNameChars.indexOf(uri[k]) >=0) {
6347
+ canSplit = false; break;
6348
+ }
6349
+ }
6350
+ if (canSplit) {
6351
+ var localid = uri.slice(j+1);
6352
+ var namesp = uri.slice(0,j+1);
6353
+ if (this.defaultNamespace && this.defaultNamespace == namesp
6354
+ && this.flags.indexOf('d') < 0) {// d -> suppress default
6355
+ if (this.flags.indexOf('k') >= 0 &&
6356
+ this.keyords.indexOf(localid) <0)
6357
+ return localid;
6358
+ return ':' + localid;
6359
+ }
6360
+ var prefix = this.prefixes[namesp];
6361
+ if (prefix) {
6362
+ this.namespacesUsed[namesp] = true;
6363
+ return prefix + ':' + localid;
6364
+ }
6365
+ if (uri.slice(0, j) == this.base)
6366
+ return '<#' + localid + '>';
6367
+ // Fall though if can't do qname
6368
+ }
6369
+ }
6370
+ if (this.flags.indexOf('r') < 0 && this.base)
6371
+ uri = $rdf.Util.uri.refTo(this.base, uri);
6372
+ else if (this.flags.indexOf('u') >= 0)
6373
+ uri = backslashUify(uri);
6374
+ else uri = hexify(uri);
6375
+ return '<'+uri+'>';
6376
+ }
6377
+
6378
+
6379
+ // String ecaping utilities
6380
+
6381
+
6382
+ function hexify(str) { // also used in parser
6383
+ return encodeURI(str);
6384
+ }
6385
+
6386
+
6387
+ function backslashUify(str) {
6388
+ var res = '', k;
6389
+ for (var i=0; i<str.length; i++) {
6390
+ k = str.charCodeAt(i);
6391
+ if (k>65535)
6392
+ res += '\\U' + ('00000000'+k.toString(16)).slice(-8); // convert to upper?
6393
+ else if (k>126)
6394
+ res += '\\u' + ('0000'+k.toString(16)).slice(-4);
6395
+ else
6396
+ res += str[i];
6397
+ }
6398
+ return res;
6399
+ }
6400
+
6401
+
6402
+ ///////////////////////////// Quad store serialization
6403
+
6404
+
6405
+ // @para. write - a function taking a single string to be output
6406
+ //
6407
+ __Serializer.prototype.writeStore = function(write) {
6408
+
6409
+ var kb = this.store;
6410
+ var fetcher = kb.fetcher;
6411
+ var session = fetcher && fetcher.appNode;
6412
+
6413
+ // Everything we know from experience just write out.
6414
+ if (session) write(this.statementsToN3(kb.statementsMatching(
6415
+ undefined, undefined, undefined, session)));
6416
+
6417
+ var sources = this.store.index[3];
6418
+ for (s in sources) { // -> assume we can use -> as short for log:semantics
6419
+ var source = kb.fromNT(s);
6420
+ if (session && source.sameTerm(session)) continue;
6421
+ write('\n'+ this.atomicTermToN3(source)+' -> { '+ this.statementsToN3(kb.statementsMatching(
6422
+ undefined, undefined, undefined, source)) + ' }.\n');
6423
+ }
6424
+ }
6425
+
6426
+
6427
+
6428
+
6429
+
6430
+ //////////////////////////////////////////////// XML serialization
6431
+
6432
+ __Serializer.prototype.statementsToXML = function(sts) {
6433
+ var indent = 4;
6434
+ var width = 80;
6435
+
6436
+ var namespaceCounts = []; // which have been used
6437
+ namespaceCounts['http://www.w3.org/1999/02/22-rdf-syntax-ns#'] = true;
6438
+
6439
+ var liPrefix = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_'; //prefix for ordered list items
6440
+
6441
+ ////////////////////////// Arrange the bits of XML text
6442
+
6443
+ var spaces=function(n) {
6444
+ var s='';
6445
+ for(var i=0; i<n; i++) s+=' ';
6446
+ return s
6447
+ }
6448
+
6449
+ var XMLtreeToLine = function(tree) {
6450
+ var str = '';
6451
+ for (var i=0; i<tree.length; i++) {
6452
+ var branch = tree[i];
6453
+ var s2 = (typeof branch == 'string') ? branch : XMLtreeToLine(branch);
6454
+ str += s2;
6455
+ }
6456
+ return str;
6457
+ }
6458
+
6459
+ // Convert a nested tree of lists and strings to a string
6460
+ var XMLtreeToString = function(tree, level) {
6461
+ var str = '';
6462
+ var lastLength = 100000;
6463
+ if (!level) level = 0;
6464
+ for (var i=0; i<tree.length; i++) {
6465
+ var branch = tree[i];
6466
+ if (typeof branch != 'string') {
6467
+ var substr = XMLtreeToString(branch, level +1);
6468
+ if (
6469
+ substr.length < 10*(width-indent*level)
6470
+ && substr.indexOf('"""') < 0) {// Don't mess up multiline strings
6471
+ var line = XMLtreeToLine(branch);
6472
+ if (line.length < (width-indent*level)) {
6473
+ branch = ' '+line; // @@ Hack: treat as string below
6474
+ substr = ''
6475
+ }
6476
+ }
6477
+ if (substr) lastLength = 10000;
6478
+ str += substr;
6479
+ }
6480
+ if (typeof branch == 'string') {
6481
+ if (lastLength < (indent*level+4)) { // continue
6482
+ str = str.slice(0,-1) + ' ' + branch + '\n';
6483
+ lastLength += branch.length + 1;
6484
+ } else {
6485
+ var line = spaces(indent*level) +branch;
6486
+ str += line +'\n';
6487
+ lastLength = line.length;
6488
+ }
6489
+
6490
+ } else { // not string
6491
+ }
6492
+ }
6493
+ return str;
6494
+ };
6495
+
6496
+ function statementListToXMLTree(statements) {
6497
+ this.suggestPrefix('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
6498
+ var stats = this.rootSubjects(statements);
6499
+ var roots = stats.roots;
6500
+ var results = []
6501
+ for (var i=0; i<roots.length; i++) {
6502
+ root = roots[i];
6503
+ results.push(subjectXMLTree(root, stats))
6504
+ }
6505
+ return results;
6506
+ }
6507
+ statementListToXMLTree = statementListToXMLTree.bind(this);
6508
+
6509
+ function escapeForXML(str) {
6510
+ if (typeof str == 'undefined') return '@@@undefined@@@@';
6511
+ return str.replace(/[&<"]/g, function(m) {
6512
+ switch(m[0]) {
6513
+ case '&':
6514
+ return '&amp;';
6515
+ case '<':
6516
+ return '&lt;';
6517
+ case '"':
6518
+ return '&quot;'; //'
6519
+ }
6520
+ });
6521
+ }
6522
+
6523
+ function relURI(term) {
6524
+ return escapeForXML((this.base) ? $rdf.Util.uri.refTo(this.base, term.uri) : term.uri);
6525
+ }
6526
+ relURI = relURI.bind(this);
6527
+
6528
+ // The tree for a subject
6529
+ function subjectXMLTree(subject, stats) {
6530
+ var results = [];
6531
+ var type, t, st, pred;
6532
+ var sts = stats.subjects[this.toStr(subject)]; // relevant statements
6533
+ if (typeof sts == 'undefined') {
6534
+ throw('Serializing XML - Cant find statements for '+subject);
6535
+ }
6536
+
6537
+
6538
+ // Sort only on the predicate, leave the order at object
6539
+ // level undisturbed. This leaves multilingual content in
6540
+ // the order of entry (for partner literals), which helps
6541
+ // readability.
6542
+ //
6543
+ // For the predicate sort, we attempt to split the uri
6544
+ // as a hint to the sequence
6545
+ sts.sort(function(a,b) {
6546
+ var ap = a.predicate.uri;
6547
+ var bp = b.predicate.uri;
6548
+ if(ap.substring(0,liPrefix.length) == liPrefix || bp.substring(0,liPrefix.length) == liPrefix) { //we're only interested in sorting list items
6549
+ return ap.localeCompare(bp);
6550
+ }
6551
+
6552
+ var as = ap.substring(liPrefix.length);
6553
+ var bs = bp.substring(liPrefix.length);
6554
+ var an = parseInt(as);
6555
+ var bn = parseInt(bs);
6556
+ if(isNaN(an) || isNaN(bn) ||
6557
+ an != as || bn != bs) { //we only care about integers
6558
+ return ap.localeCompare(bp);
6559
+ }
6560
+
6561
+ return an - bn;
6562
+ });
6563
+
6564
+
6565
+ for (var i=0; i<sts.length; i++) {
6566
+ st = sts[i];
6567
+ // look for a type
6568
+ if(st.predicate.uri == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' && !type && st.object.termType == "symbol") {
6569
+ type = st.object;
6570
+ continue; //don't include it as a child element
6571
+ }
6572
+
6573
+ // see whether predicate can be replaced with "li"
6574
+ pred = st.predicate;
6575
+ if(pred.uri.substr(0, liPrefix.length) == liPrefix) {
6576
+ var number = pred.uri.substr(liPrefix.length);
6577
+ // make sure these are actually numeric list items
6578
+ var intNumber = parseInt(number);
6579
+ if(number == intNumber.toString()) {
6580
+ // was numeric; don't need to worry about ordering since we've already
6581
+ // sorted the statements
6582
+ pred = new $rdf.Symbol('http://www.w3.org/1999/02/22-rdf-syntax-ns#li');
6583
+ }
6584
+ }
6585
+
6586
+ t = qname(pred);
6587
+ switch (st.object.termType) {
6588
+ case 'bnode':
6589
+ if(stats.incoming[st.object].length == 1) { //there should always be something in the incoming array for a bnode
6590
+ results = results.concat(['<'+ t +'>',
6591
+ subjectXMLTree(st.object, stats),
6592
+ '</'+ t +'>']);
6593
+ } else {
6594
+ results = results.concat(['<'+ t +' rdf:nodeID="'
6595
+ +st.object.toNT().slice(2)+'"/>']);
6596
+ }
6597
+ break;
6598
+ case 'symbol':
6599
+ results = results.concat(['<'+ t +' rdf:resource="'
6600
+ + relURI(st.object)+'"/>']);
6601
+ break;
6602
+ case 'literal':
6603
+ results = results.concat(['<'+ t
6604
+ + (st.object.dt ? ' rdf:datatype="'+escapeForXML(st.object.dt.uri)+'"' : '')
6605
+ + (st.object.lang ? ' xml:lang="'+st.object.lang+'"' : '')
6606
+ + '>' + escapeForXML(st.object.value)
6607
+ + '</'+ t +'>']);
6608
+ break;
6609
+ case 'collection':
6610
+ results = results.concat(['<'+ t +' rdf:parseType="Collection">',
6611
+ collectionXMLTree(st.object, stats),
6612
+ '</'+ t +'>']);
6613
+ break;
6614
+ default:
6615
+ throw "Can't serialize object of type "+st.object.termType +" into XML";
6616
+ } // switch
6617
+ }
6618
+
6619
+ var tag = type ? qname(type) : 'rdf:Description';
6620
+
6621
+ var attrs = '';
6622
+ if (subject.termType == 'bnode') {
6623
+ if(!stats.incoming[subject] || stats.incoming[subject].length != 1) { // not an anonymous bnode
6624
+ attrs = ' rdf:nodeID="'+subject.toNT().slice(2)+'"';
6625
+ }
6626
+ } else {
6627
+ attrs = ' rdf:about="'+ relURI(subject)+'"';
6628
+ }
6629
+
6630
+ return [ '<' + tag + attrs + '>' ].concat([results]).concat(["</"+ tag +">"]);
6631
+ }
6632
+
6633
+ subjectXMLTree = subjectXMLTree.bind(this);
6634
+
6635
+ function collectionXMLTree(subject, stats) {
6636
+ var res = []
6637
+ for (var i=0; i< subject.elements.length; i++) {
6638
+ res.push(subjectXMLTree(subject.elements[i], stats));
6639
+ }
6640
+ return res;
6641
+ }
6642
+
6643
+ // The property tree for a single subject or anonymos node
6644
+ function propertyXMLTree(subject, stats) {
6645
+ var results = []
6646
+ var sts = stats.subjects[this.toStr(subject)]; // relevant statements
6647
+ if (sts == undefined) return results; // No relevant statements
6648
+ sts.sort();
6649
+ for (var i=0; i<sts.length; i++) {
6650
+ var st = sts[i];
6651
+ switch (st.object.termType) {
6652
+ case 'bnode':
6653
+ if(stats.rootsHash[st.object.toNT()]) { // This bnode has been done as a root -- no content here @@ what bout first time
6654
+ results = results.concat(['<'+qname(st.predicate)+' rdf:nodeID="'+st.object.toNT().slice(2)+'">',
6655
+ '</'+qname(st.predicate)+'>']);
6656
+ } else {
6657
+ results = results.concat(['<'+qname(st.predicate)+' rdf:parseType="Resource">',
6658
+ propertyXMLTree(st.object, stats),
6659
+ '</'+qname(st.predicate)+'>']);
6660
+ }
6661
+ break;
6662
+ case 'symbol':
6663
+ results = results.concat(['<'+qname(st.predicate)+' rdf:resource="'
6664
+ + relURI(st.object)+'"/>']);
6665
+ break;
6666
+ case 'literal':
6667
+ results = results.concat(['<'+qname(st.predicate)
6668
+ + (st.object.datatype ? ' rdf:datatype="'+escapeForXML(st.object.datatype.uri)+'"' : '')
6669
+ + (st.object.lang ? ' xml:lang="'+st.object.lang+'"' : '')
6670
+ + '>' + escapeForXML(st.object.value)
6671
+ + '</'+qname(st.predicate)+'>']);
6672
+ break;
6673
+ case 'collection':
6674
+ results = results.concat(['<'+qname(st.predicate)+' rdf:parseType="Collection">',
6675
+ collectionXMLTree(st.object, stats),
6676
+ '</'+qname(st.predicate)+'>']);
6677
+ break;
6678
+ default:
6679
+ throw "Can't serialize object of type "+st.object.termType +" into XML";
6680
+
6681
+ } // switch
6682
+ }
6683
+ return results;
6684
+ }
6685
+ propertyXMLTree = propertyXMLTree.bind(this);
6686
+
6687
+ function qname(term) {
6688
+ var uri = term.uri;
6689
+
6690
+ var j = uri.indexOf('#');
6691
+ if (j<0 && this.flags.indexOf('/') < 0) {
6692
+ j = uri.lastIndexOf('/');
6693
+ }
6694
+ if (j < 0) throw ("Cannot make qname out of <"+uri+">")
6695
+
6696
+ var canSplit = true;
6697
+ for (var k=j+1; k<uri.length; k++) {
6698
+ if (__Serializer.prototype._notNameChars.indexOf(uri[k]) >=0) {
6699
+ throw ('Invalid character "'+uri[k] +'" cannot be in XML qname for URI: '+uri);
6700
+ }
6701
+ }
6702
+ var localid = uri.slice(j+1);
6703
+ var namesp = uri.slice(0,j+1);
6704
+ if (this.defaultNamespace && this.defaultNamespace == namesp
6705
+ && this.flags.indexOf('d') < 0) {// d -> suppress default
6706
+ return localid;
6707
+ }
6708
+ var prefix = this.prefixes[namesp];
6709
+ if (!prefix) prefix = this.makeUpPrefix(namesp);
6710
+ namespaceCounts[namesp] = true;
6711
+ return prefix + ':' + localid;
6712
+ // throw ('No prefix for namespace "'+namesp +'" for XML qname for '+uri+', namespaces: '+sz.prefixes+' sz='+sz);
6713
+ }
6714
+ qname = qname.bind(this);
6715
+
6716
+ // Body of toXML:
6717
+
6718
+ var tree = statementListToXMLTree(sts);
6719
+ var str = '<rdf:RDF';
6720
+ if (this.defaultNamespace)
6721
+ str += ' xmlns="'+escapeForXML(this.defaultNamespace)+'"';
6722
+ for (var ns in namespaceCounts) {
6723
+ if (!namespaceCounts.hasOwnProperty(ns)) continue;
6724
+ str += '\n xmlns:' + this.prefixes[ns] + '="'+escapeForXML(ns)+'"';
6725
+ }
6726
+ str += '>';
6727
+
6728
+ var tree2 = [str, tree, '</rdf:RDF>']; //@@ namespace declrations
6729
+ return XMLtreeToString(tree2, -1);
6730
+
6731
+
6732
+ } // End @@ body
6733
+
6734
+ var Serializer = function( store ) {return new __Serializer( store )};
6735
+ return Serializer;
6736
+
6737
+ }();
6805
6738
  /*
6806
6739
  # Updates-Via
6807
6740
  */
@@ -6946,6 +6879,9 @@ $rdf.UpdatesVia = (function() {
6946
6879
  if (d.headers == null) {
6947
6880
  return true;
6948
6881
  }
6882
+ if (typeof WebSocket === "undefined" || WebSocket === null) {
6883
+ return true;
6884
+ }
6949
6885
  etag = d.headers['etag'];
6950
6886
  via = d.headers['updates-via'];
6951
6887
  uri = d.uri;
@@ -7028,6 +6964,7 @@ $rdf.Fetcher = function(store, timeout, async) {
7028
6964
  ns.rdfs = $rdf.Namespace("http://www.w3.org/2000/01/rdf-schema#");
7029
6965
  ns.dc = $rdf.Namespace("http://purl.org/dc/elements/1.1/");
7030
6966
 
6967
+
7031
6968
  $rdf.Fetcher.crossSiteProxy = function(uri) {
7032
6969
  if ($rdf.Fetcher.crossSiteProxyTemplate)
7033
6970
  return $rdf.Fetcher.crossSiteProxyTemplate.replace('{uri}', encodeURIComponent(uri));
@@ -7037,8 +6974,9 @@ $rdf.Fetcher = function(store, timeout, async) {
7037
6974
  if (args) {
7038
6975
  this.dom = args[0]
7039
6976
  }
7040
- this.recv = function(xhr) {
6977
+ this.handlerFactory = function(xhr) {
7041
6978
  xhr.handle = function(cb) {
6979
+ //sf.addStatus(xhr.req, 'parsing soon as RDF/XML...');
7042
6980
  var kb = sf.store;
7043
6981
  if (!this.dom) this.dom = $rdf.Util.parseXML(xhr.responseText);
7044
6982
  /* {
@@ -7053,7 +6991,6 @@ $rdf.Fetcher = function(store, timeout, async) {
7053
6991
  }
7054
6992
  */
7055
6993
  var root = this.dom.documentElement;
7056
- //some simple syntax issue should be dealt here, I think
7057
6994
  if (root.nodeName == 'parsererror') { //@@ Mozilla only See issue/issue110
7058
6995
  sf.failFetch(xhr, "Badly formed XML in " + xhr.uri.uri); //have to fail the request
7059
6996
  throw new Error("Badly formed XML in " + xhr.uri.uri); //@@ Add details
@@ -7061,17 +6998,13 @@ $rdf.Fetcher = function(store, timeout, async) {
7061
6998
  // Find the last URI we actual URI in a series of redirects
7062
6999
  // (xhr.uri.uri is the original one)
7063
7000
  var lastRequested = kb.any(xhr.req, ns.link('requestedURI'));
7064
- //dump('lastRequested 1:'+lastRequested+'\n')
7065
7001
  if (!lastRequested) {
7066
- //dump("Eh? No last requested for "+xhr.uri+"\n");
7067
7002
  lastRequested = xhr.uri;
7068
7003
  } else {
7069
7004
  lastRequested = kb.sym(lastRequested.value);
7070
- //dump('lastRequested 2:'+lastRequested+'\n')
7071
7005
  }
7072
- //dump('lastRequested 3:'+lastRequested+'\n')
7073
7006
  var parser = new $rdf.RDFParser(kb);
7074
- sf.addStatus(xhr.req, 'parsing as RDF/XML...');
7007
+ // sf.addStatus(xhr.req, 'parsing as RDF/XML...');
7075
7008
  parser.parse(this.dom, lastRequested.uri, lastRequested);
7076
7009
  kb.add(lastRequested, ns.rdf('type'), ns.link('RDFDocument'), sf.appNode);
7077
7010
  cb();
@@ -7096,7 +7029,7 @@ $rdf.Fetcher = function(store, timeout, async) {
7096
7029
  if (args) {
7097
7030
  this.dom = args[0]
7098
7031
  }
7099
- this.recv = function(xhr) {
7032
+ this.handlerFactory = function(xhr) {
7100
7033
  xhr.handle = function(cb) {
7101
7034
  if (!this.dom) {
7102
7035
  var dparser;
@@ -7146,6 +7079,7 @@ $rdf.Fetcher = function(store, timeout, async) {
7146
7079
  // Do RDFa here
7147
7080
  if ($rdf.rdfa && $rdf.rdfa.parse)
7148
7081
  $rdf.rdfa.parse(this.dom, kb, xhr.uri.uri);
7082
+ cb(); // Fire done callbacks
7149
7083
  }
7150
7084
  }
7151
7085
  };
@@ -7164,7 +7098,7 @@ $rdf.Fetcher = function(store, timeout, async) {
7164
7098
  /******************************************************/
7165
7099
 
7166
7100
  $rdf.Fetcher.XMLHandler = function() {
7167
- this.recv = function(xhr) {
7101
+ this.handlerFactory = function(xhr) {
7168
7102
  xhr.handle = function(cb) {
7169
7103
  var kb = sf.store
7170
7104
  var dparser;
@@ -7248,7 +7182,7 @@ $rdf.Fetcher = function(store, timeout, async) {
7248
7182
  $rdf.Fetcher.XMLHandler.pattern = new RegExp("(text|application)/(.*)xml");
7249
7183
 
7250
7184
  $rdf.Fetcher.HTMLHandler = function() {
7251
- this.recv = function(xhr) {
7185
+ this.handlerFactory = function(xhr) {
7252
7186
  xhr.handle = function(cb) {
7253
7187
  var rt = xhr.responseText
7254
7188
  // We only handle XHTML so we have to figure out if this is XML
@@ -7305,7 +7239,7 @@ $rdf.Fetcher = function(store, timeout, async) {
7305
7239
  /***********************************************/
7306
7240
 
7307
7241
  $rdf.Fetcher.TextHandler = function() {
7308
- this.recv = function(xhr) {
7242
+ this.handlerFactory = function(xhr) {
7309
7243
  xhr.handle = function(cb) {
7310
7244
  // We only speak dialects of XML right now. Is this XML?
7311
7245
  var rt = xhr.responseText
@@ -7349,9 +7283,11 @@ $rdf.Fetcher = function(store, timeout, async) {
7349
7283
  /***********************************************/
7350
7284
 
7351
7285
  $rdf.Fetcher.N3Handler = function() {
7352
- this.recv = function(xhr) {
7286
+ this.handlerFactory = function(xhr) {
7353
7287
  xhr.handle = function(cb) {
7354
7288
  // Parse the text of this non-XML file
7289
+ $rdf.log.debug("web.js: Parsing as N3 " + xhr.uri.uri); // @@@@ comment me out
7290
+ //sf.addStatus(xhr.req, "N3 not parsed yet...")
7355
7291
  var rt = xhr.responseText
7356
7292
  var p = $rdf.N3Parser(kb, kb, xhr.uri.uri, xhr.uri.uri, null, null, "", null)
7357
7293
  // p.loadBuf(xhr.responseText)
@@ -7359,13 +7295,13 @@ $rdf.Fetcher = function(store, timeout, async) {
7359
7295
  p.loadBuf(xhr.responseText)
7360
7296
 
7361
7297
  } catch (e) {
7362
- var msg = ("Error trying to parse " + xhr.uri + ' as Notation3:\n' + e +':\n'+e.stack)
7298
+ var msg = ("Error trying to parse " + xhr.uri + " as Notation3:\n" + e +':\n'+e.stack)
7363
7299
  // dump(msg+"\n")
7364
7300
  sf.failFetch(xhr, msg)
7365
7301
  return;
7366
7302
  }
7367
7303
 
7368
- sf.addStatus(xhr.req, 'N3 parsed: ' + p.statementCount + ' statements in ' + p.lines + ' lines.')
7304
+ sf.addStatus(xhr.req, "N3 parsed: " + p.statementCount + " triples in " + p.lines + " lines.")
7369
7305
  sf.store.add(xhr.uri, ns.rdf('type'), ns.link('RDFDocument'), sf.appNode);
7370
7306
  args = [xhr.uri.uri]; // Other args needed ever?
7371
7307
  sf.doneFetch(xhr, args)
@@ -7416,7 +7352,7 @@ $rdf.Fetcher = function(store, timeout, async) {
7416
7352
  ';\n\t $rdf.Fetcher.HTMLHandler='+$rdf.Fetcher.HTMLHandler+'\n' +
7417
7353
  '\n\tsf.handlers='+sf.handlers+'\n'
7418
7354
  }
7419
- (new handler(args)).recv(xhr);
7355
+ (new handler(args)).handlerFactory(xhr);
7420
7356
  xhr.handle(cb)
7421
7357
  }
7422
7358
 
@@ -7426,7 +7362,12 @@ $rdf.Fetcher = function(store, timeout, async) {
7426
7362
  status = "[" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + "." + now.getMilliseconds() + "] " + status;
7427
7363
  //</Debug>
7428
7364
  var kb = this.store
7429
- kb.the(req, ns.link('status')).append(kb.literal(status))
7365
+ var s = kb.the(req, ns.link('status'));
7366
+ if (s && s.append) {
7367
+ s.append(kb.literal(status));
7368
+ } else {
7369
+ $rdf.log.warn("web.js: No list to add to: " + s + ',' + status); // @@@
7370
+ };
7430
7371
  }
7431
7372
 
7432
7373
  // Record errors in the system on failure
@@ -7435,7 +7376,7 @@ $rdf.Fetcher = function(store, timeout, async) {
7435
7376
  this.addStatus(xhr.req, status)
7436
7377
  kb.add(xhr.uri, ns.link('error'), status)
7437
7378
  this.requested[$rdf.uri.docpart(xhr.uri.uri)] = false
7438
- this.fireCallbacks('fail', [xhr.requestedURI])
7379
+ this.fireCallbacks('fail', [xhr.requestedURI, status])
7439
7380
  xhr.abort()
7440
7381
  return xhr
7441
7382
  }
@@ -7515,13 +7456,22 @@ $rdf.Fetcher = function(store, timeout, async) {
7515
7456
 
7516
7457
 
7517
7458
  /* Ask for a doc to be loaded if necessary then call back
7518
- **/
7459
+ **
7460
+ ** Changed 2013-08-20: Added (ok, body) params to callback
7461
+ **
7462
+ **/
7519
7463
  this.nowOrWhenFetched = function(uri, referringTerm, callback) {
7520
7464
  var sta = this.getState(uri);
7521
- if (sta == 'fetched') return callback();
7465
+ if (sta == 'fetched') return callback(true);
7522
7466
  this.addCallback('done', function(uri2) {
7523
7467
  if (uri2 == uri ||
7524
- ( $rdf.Fetcher.crossSiteProxy(uri) == uri2 )) callback();
7468
+ ( $rdf.Fetcher.crossSiteProxy(uri) == uri2 )) callback(true);
7469
+ return (uri2 != uri); // Call me again?
7470
+ });
7471
+ this.addCallback('fail', function(uri2, status) {
7472
+ if (uri2 == uri ||
7473
+ ( $rdf.Fetcher.crossSiteProxy(uri) == uri2 )) callback(
7474
+ false, "Asynch fetch fail: " + status + " for " + uri);
7525
7475
  return (uri2 != uri); // Call me again?
7526
7476
  });
7527
7477
  if (sta == 'unrequested') this.requestURI(
@@ -7530,6 +7480,30 @@ $rdf.Fetcher = function(store, timeout, async) {
7530
7480
 
7531
7481
 
7532
7482
 
7483
+ // Look up response header
7484
+ //
7485
+ // Returns: a list of header values found in a stored HTTP response
7486
+ // or [] if response was found but no header found
7487
+ // or undefined if no response is available.
7488
+ //
7489
+ this.getHeader = function(doc, header) {
7490
+ var kb = this.store;
7491
+ var requests = kb.each(undefined, tabulator.ns.link("requestedURI"), doc.uri);
7492
+ for (var r=0; r<requests.length; r++) {
7493
+ request = requests[r];
7494
+ if (request !== undefined) {
7495
+ var response = kb.any(request, tabulator.ns.link("response"));
7496
+ if (request !== undefined) {
7497
+ var results = kb.each(response, tabulator.ns.httph(header.toLowerCase()));
7498
+ if (results.length) {
7499
+ return results.map(function(v){return v.value});
7500
+ }
7501
+ return [];
7502
+ }
7503
+ }
7504
+ }
7505
+ return undefined;
7506
+ };
7533
7507
 
7534
7508
 
7535
7509
  /** Requests a document URI and arranges to load the document.
@@ -7679,9 +7653,10 @@ $rdf.Fetcher = function(store, timeout, async) {
7679
7653
  if ($rdf.uri.protocol(xhr.uri.uri) == 'http' || $rdf.uri.protocol(xhr.uri.uri) == 'https') {
7680
7654
  xhr.headers = $rdf.Util.getHTTPHeaders(xhr)
7681
7655
  for (var h in xhr.headers) { // trim below for Safari - adds a CR!
7682
- kb.add(response, ns.httph(h), xhr.headers[h].trim(), response)
7656
+ kb.add(response, ns.httph(h.toLowerCase()), xhr.headers[h].trim(), response)
7683
7657
  }
7684
7658
  }
7659
+
7685
7660
  sf.fireCallbacks('headers', [{uri: docuri, headers: xhr.headers}]);
7686
7661
 
7687
7662
  if (xhr.status >= 400) { // For extra dignostics, keep the reply
@@ -7754,7 +7729,6 @@ $rdf.Fetcher = function(store, timeout, async) {
7754
7729
  sf.requested[udoc] = true
7755
7730
  }
7756
7731
 
7757
-
7758
7732
  for (var x = 0; x < sf.handlers.length; x++) {
7759
7733
  if (xhr.headers['content-type'] && xhr.headers['content-type'].match(sf.handlers[x].pattern)) {
7760
7734
  handler = new sf.handlers[x]()
@@ -7763,7 +7737,10 @@ $rdf.Fetcher = function(store, timeout, async) {
7763
7737
  }
7764
7738
  }
7765
7739
 
7766
- var link = xhr.getResponseHeader('link');
7740
+ var link;
7741
+ try {
7742
+ link = xhr.getResponseHeader('link');
7743
+ }catch(e){}
7767
7744
  if (link) {
7768
7745
  var rel = null;
7769
7746
  var arg = link.replace(/ /g, '').split(';');
@@ -7781,10 +7758,17 @@ $rdf.Fetcher = function(store, timeout, async) {
7781
7758
 
7782
7759
 
7783
7760
  if (handler) {
7784
- handler.recv(xhr)
7761
+ try {
7762
+ handler.handlerFactory(xhr);
7763
+ } catch(e) { // Try to avoid silent errors
7764
+ sf.failFetch(xhr, "Exception handling content-type " + xhr.headers['content-type'] + ' was: '+e);
7765
+ };
7785
7766
  } else {
7786
- sf.failFetch(xhr, "Unhandled content type: " + xhr.headers['content-type']+
7787
- ", readyState = "+xhr.readyState);
7767
+ sf.doneFetch(xhr, args); // Not a problem, we just don't extract data.
7768
+ /*
7769
+ // sf.failFetch(xhr, "Unhandled content type: " + xhr.headers['content-type']+
7770
+ // ", readyState = "+xhr.readyState);
7771
+ */
7788
7772
  return;
7789
7773
  }
7790
7774
  };
@@ -7794,6 +7778,9 @@ $rdf.Fetcher = function(store, timeout, async) {
7794
7778
  // LOADING: 3
7795
7779
  // OPENED: 1
7796
7780
  // UNSENT: 0
7781
+
7782
+ // $rdf.log.debug("web.js: XHR " + xhr.uri.uri + ' readyState='+xhr.readyState); // @@@@ comment me out
7783
+
7797
7784
  switch (xhr.readyState) {
7798
7785
  case 0:
7799
7786
  var uri = xhr.uri.uri, newURI;
@@ -7860,8 +7847,10 @@ $rdf.Fetcher = function(store, timeout, async) {
7860
7847
  sf.doneFetch(xhr, args)
7861
7848
  })
7862
7849
  } else {
7863
- sf.failFetch(xhr, "HTTP failed unusually. (no handler set) (cross-site violation? no net?) for <"+
7864
- docuri+">");
7850
+ sf.addStatus(xhr.req, "Fetch OK. No known semantics.");
7851
+ sf.doneFetch(xhr, args);
7852
+ //sf.failFetch(xhr, "HTTP failed unusually. (no handler set) (x-site violation? no net?) for <"+
7853
+ // docuri+">");
7865
7854
  }
7866
7855
  break
7867
7856
  } // switch
@@ -8247,4 +8236,22 @@ $rdf.parse = function parse(str, kb, base, contentType) {
8247
8236
 
8248
8237
 
8249
8238
  // ends
8250
- return $rdf;}()
8239
+
8240
+ // Handle node, amd, and global systems
8241
+ if (typeof exports !== 'undefined') {
8242
+ if (typeof module !== 'undefined' && module.exports) {
8243
+ exports = module.exports = $rdf;
8244
+ }
8245
+ exports.$rdf = $rdf;
8246
+ }
8247
+ else {
8248
+ if (typeof define === 'function' && define.amd) {
8249
+ define('rdflib', function() {
8250
+ return $rdf;
8251
+ });
8252
+ }
8253
+
8254
+ // Leak a global regardless of module system
8255
+ root['$rdf'] = $rdf;
8256
+ }
8257
+ })(this);