home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / python-support / python-rdflib / rdflib / syntax / parsers / RDFXMLHandler.py < prev    next >
Encoding:
Python Source  |  2007-04-04  |  19.2 KB  |  518 lines

  1. # Copyright (c) 2002, Daniel Krech, http://eikeon.com/
  2. # All rights reserved.
  3. #
  4. # Redistribution and use in source and binary forms, with or without
  5. # modification, are permitted provided that the following conditions are
  6. # met:
  7. #
  8. #   * Redistributions of source code must retain the above copyright
  9. # notice, this list of conditions and the following disclaimer.
  10. #
  11. #   * Redistributions in binary form must reproduce the above
  12. # copyright notice, this list of conditions and the following
  13. # disclaimer in the documentation and/or other materials provided
  14. # with the distribution.
  15. #
  16. #   * Neither the name of Daniel Krech nor the names of its
  17. # contributors may be used to endorse or promote products derived
  18. # from this software without specific prior written permission.
  19. #
  20. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31.  
  32. """
  33. """
  34. from rdflib import RDF, RDFS
  35. from rdflib import URIRef, BNode, Literal
  36. from rdflib.exceptions import ParserError, Error
  37. from rdflib.syntax.xml_names import is_ncname
  38.  
  39. from xml.sax.saxutils import handler, quoteattr, escape
  40. from urlparse import urljoin, urldefrag
  41.  
  42. RDFNS = RDF.RDFNS
  43.  
  44. # http://www.w3.org/TR/rdf-syntax-grammar/#eventterm-attribute-URI
  45. # A mapping from unqualified terms to there qualified version.
  46. UNQUALIFIED = {"about" : RDF.about,
  47.                "ID" : RDF.ID,
  48.                "type" : RDF.type,
  49.                "resource": RDF.resource,
  50.                "parseType": RDF.parseType}
  51.  
  52. # http://www.w3.org/TR/rdf-syntax-grammar/#coreSyntaxTerms
  53. CORE_SYNTAX_TERMS = [RDF.RDF, RDF.ID, RDF.about, RDF.parseType, RDF.resource, RDF.nodeID, RDF.datatype]
  54.  
  55. # http://www.w3.org/TR/rdf-syntax-grammar/#syntaxTerms
  56. SYNTAX_TERMS = CORE_SYNTAX_TERMS + [RDF.Description, RDF.li]
  57.  
  58. # http://www.w3.org/TR/rdf-syntax-grammar/#oldTerms
  59. OLD_TERMS = [RDFNS["aboutEach"], RDFNS["aboutEachPrefix"], RDFNS["bagID"]]
  60.  
  61. NODE_ELEMENT_EXCEPTIONS = CORE_SYNTAX_TERMS + [RDF.li,] + OLD_TERMS
  62. NODE_ELEMENT_ATTRIBUTES = [RDF.ID, RDF.nodeID, RDF.about]
  63.  
  64. PROPERTY_ELEMENT_EXCEPTIONS = CORE_SYNTAX_TERMS + [RDF.Description,] + OLD_TERMS
  65. PROPERTY_ATTRIBUTE_EXCEPTIONS = CORE_SYNTAX_TERMS + [RDF.Description, RDF.li] + OLD_TERMS
  66. PROPERTY_ELEMENT_ATTRIBUTES = [RDF.ID, RDF.resource, RDF.nodeID]
  67.  
  68. XMLNS = "http://www.w3.org/XML/1998/namespace"
  69. BASE = (XMLNS, "base")
  70. LANG = (XMLNS, "lang")
  71.  
  72.  
  73. class BagID(URIRef):
  74.     __slots__ = ['li']
  75.     def __init__(self, val):
  76.         super(URIRef, self).__init__(val)
  77.         self.li = 0
  78.  
  79.     def next_li(self):
  80.         self.li += 1
  81.         return URIRef(RDFNS + "_%s" % self.li)
  82.  
  83.  
  84. class ElementHandler(object):
  85.     __slots__ = ['start', 'char', 'end', 'li', 'id',
  86.                  'base', 'subject', 'predicate', 'object',
  87.                  'list', 'language', 'datatype', 'declared', 'data']
  88.     def __init__(self):
  89.         self.start = None
  90.         self.char = None
  91.         self.end = None
  92.         self.li = 0
  93.         self.id = None
  94.         self.base = None
  95.         self.subject = None
  96.         self.object = None
  97.         self.list = None
  98.         self.language = None
  99.         self.datatype = None
  100.         self.declared = None
  101.         self.data = None
  102.  
  103.     def next_li(self):
  104.         self.li += 1
  105.         return URIRef(RDFNS + "_%s" % self.li)
  106.  
  107.  
  108. class RDFXMLHandler(handler.ContentHandler):
  109.  
  110.     def __init__(self, store):
  111.         self.store = store
  112.         self.preserve_bnode_ids = False
  113.         self.reset()
  114.  
  115.     def reset(self):
  116.         document_element = ElementHandler()
  117.         document_element.start = self.document_element_start
  118.         document_element.end = lambda name, qname: None
  119.         self.stack = [None, document_element,]
  120.         self.ids = {} # remember IDs we have already seen
  121.         self.bnode = {}
  122.         self._ns_contexts = [{}] # contains uri -> prefix dicts
  123.         self._current_context = self._ns_contexts[-1]
  124.  
  125.     # ContentHandler methods
  126.  
  127.     def setDocumentLocator(self, locator):
  128.         self.locator = locator
  129.  
  130.     def startDocument(self):
  131.         pass
  132.  
  133.     def startPrefixMapping(self, prefix, namespace):
  134.         self._ns_contexts.append(self._current_context.copy())
  135.         self._current_context[namespace] = prefix
  136.         self.store.bind(prefix, URIRef(namespace), override=False)
  137.  
  138.     def endPrefixMapping(self, prefix):
  139.         self._current_context = self._ns_contexts[-1]
  140.         del self._ns_contexts[-1]
  141.  
  142.     def startElementNS(self, name, qname, attrs):
  143.         stack = self.stack
  144.         stack.append(ElementHandler())
  145.         current = self.current
  146.         parent = self.parent
  147.         base = attrs.get(BASE, None)
  148.         if base is not None:
  149.             base, frag = urldefrag(base)
  150.         else:
  151.             if parent:
  152.                 base = parent.base
  153.             if base is None:
  154.                 systemId = self.locator.getPublicId() or self.locator.getSystemId()
  155.                 if systemId:
  156.                     base, frag = urldefrag(systemId)
  157.         current.base = base
  158.         language = attrs.get(LANG, None)
  159.         if language is None:
  160.             if parent:
  161.                 language = parent.language
  162.         current.language = language
  163.         current.start(name, qname, attrs)
  164.  
  165.     def endElementNS(self, name, qname):
  166.         self.current.end(name, qname)
  167.         self.stack.pop()
  168.  
  169.     def characters(self, content):
  170.         char = self.current.char
  171.         if char:
  172.             char(content)
  173.  
  174.     def ignorableWhitespace(self, content):
  175.         pass
  176.  
  177.     def processingInstruction(self, target, data):
  178.         pass
  179.  
  180.     def add_reified(self, sid, (s, p, o)):
  181.         self.store.add((sid, RDF.type, RDF.Statement))
  182.         self.store.add((sid, RDF.subject, s))
  183.         self.store.add((sid, RDF.predicate, p))
  184.         self.store.add((sid, RDF.object, o))
  185.  
  186.     def error(self, message):
  187.         locator = self.locator
  188.         info = "%s:%s:%s: " % (locator.getSystemId(),
  189.                             locator.getLineNumber(), locator.getColumnNumber())
  190.         raise ParserError(info + message)
  191.  
  192.     def get_current(self):
  193.         return self.stack[-2]
  194.     # Create a read only property called current so that self.current
  195.     # give the current element handler.
  196.     current = property(get_current)
  197.  
  198.     def get_next(self):
  199.         return self.stack[-1]
  200.     # Create a read only property that gives the element handler to be
  201.     # used for the next element.
  202.     next = property(get_next)
  203.  
  204.     def get_parent(self):
  205.         return self.stack[-3]
  206.     # Create a read only property that gives the current parent
  207.     # element handler
  208.     parent = property(get_parent)
  209.  
  210.     def absolutize(self, uri):
  211.         result = urljoin(self.current.base, uri, allow_fragments=1)
  212.         if uri and uri[-1]=="#" and result[-1]!="#":
  213.             result = "%s#" % result
  214.         return URIRef(result)
  215.  
  216.     def convert(self, name, qname, attrs):
  217.         if name[0] is None:
  218.             name = URIRef(name[1])
  219.         else:
  220.             name = URIRef("".join(name))
  221.         atts = {}
  222.         for (n, v) in attrs.items(): #attrs._attrs.iteritems(): #
  223.             if n[0] is None:
  224.                 att = URIRef(n[1])
  225.             else:
  226.                 att = URIRef("".join(n))
  227.             if att.startswith(XMLNS) or att[0:3].lower()=="xml":
  228.                 pass
  229.             elif att in UNQUALIFIED:
  230.                 #if not RDFNS[att] in atts:
  231.                 atts[RDFNS[att]] = v
  232.             else:
  233.                 atts[URIRef(att)] = v
  234.         return name, atts
  235.  
  236.     def document_element_start(self, name, qname, attrs):
  237.         if name[0] and URIRef("".join(name)) == RDF.RDF:
  238.             next = self.next
  239.             next.start = self.node_element_start
  240.             next.end = self.node_element_end
  241.         else:
  242.             self.node_element_start(name, qname, attrs)
  243.             #self.current.end = self.node_element_end
  244.             # TODO... set end to something that sets start such that
  245.             # another element will cause error
  246.  
  247.  
  248.     def node_element_start(self, name, qname, attrs):
  249.         name, atts = self.convert(name, qname, attrs)
  250.         current = self.current
  251.         absolutize = self.absolutize
  252.         next = self.next
  253.         next.start = self.property_element_start
  254.         next.end = self.property_element_end
  255.  
  256.         if name in NODE_ELEMENT_EXCEPTIONS:
  257.             self.error("Invalid node element URI: %s" % name)
  258.  
  259.         if RDF.ID in atts:
  260.             if RDF.about in atts or RDF.nodeID in atts:
  261.                 self.error("Can have at most one of rdf:ID, rdf:about, and rdf:nodeID")
  262.  
  263.             id = atts[RDF.ID]
  264.             if not is_ncname(id):
  265.                 self.error("rdf:ID value is not a valid NCName: %s" % id)
  266.             subject = absolutize("#%s" % id)
  267.             if subject in self.ids:
  268.                 self.error("two elements cannot use the same ID: '%s'" % subject)
  269.             self.ids[subject] = 1 # IDs can only appear once within a document
  270.         elif RDF.nodeID in atts:
  271.             if RDF.ID in atts or RDF.about in atts:
  272.                 self.error("Can have at most one of rdf:ID, rdf:about, and rdf:nodeID")
  273.             nodeID = atts[RDF.nodeID]
  274.             if not is_ncname(nodeID):
  275.                 self.error("rdf:nodeID value is not a valid NCName: %s" % nodeID)
  276.             if self.preserve_bnode_ids is False:
  277.                 if nodeID in self.bnode:
  278.                     subject = self.bnode[nodeID]
  279.                 else:
  280.                     subject = BNode()
  281.                     self.bnode[nodeID] = subject
  282.             else:
  283.                 subject = BNode(nodeID)
  284.         elif RDF.about in atts:
  285.             if RDF.ID in atts or RDF.nodeID in atts:
  286.                 self.error("Can have at most one of rdf:ID, rdf:about, and rdf:nodeID")
  287.             subject = absolutize(atts[RDF.about])
  288.         else:
  289.             subject = BNode()
  290.  
  291.         if name!=RDF.Description: # S1
  292.             self.store.add((subject, RDF.type, absolutize(name)))
  293.  
  294.         language = current.language
  295.         for att in atts:
  296.             if not att.startswith(RDFNS):
  297.                 predicate = absolutize(att)
  298.                 try:
  299.                     object = Literal(atts[att], language)
  300.                 except Error, e:
  301.                     self.error(e.msg)
  302.             elif att==RDF.type: #S2
  303.                 predicate = RDF.type
  304.                 object = absolutize(atts[RDF.type])
  305.             elif att in NODE_ELEMENT_ATTRIBUTES:
  306.                 continue
  307.             elif att in PROPERTY_ATTRIBUTE_EXCEPTIONS: #S3
  308.                 self.error("Invalid property attribute URI: %s" % att)
  309.                 continue # for when error does not throw an exception
  310.             else:
  311.                 predicate = absolutize(att)
  312.                 try:
  313.                     object = Literal(atts[att], language)
  314.                 except Error, e:
  315.                     self.error(e.msg)
  316.             self.store.add((subject, predicate, object))
  317.  
  318.         current.subject = subject
  319.  
  320.  
  321.     def node_element_end(self, name, qname):
  322.         self.parent.object = self.current.subject
  323.  
  324.     def property_element_start(self, name, qname, attrs):
  325.         name, atts = self.convert(name, qname, attrs)
  326.         current = self.current
  327.         absolutize = self.absolutize
  328.         next = self.next
  329.         object = None
  330.         current.data = None
  331.         current.list = None
  332.  
  333.         if not name.startswith(RDFNS):
  334.             current.predicate = absolutize(name)
  335.         elif name==RDF.li:
  336.             current.predicate = current.next_li()
  337.         elif name in PROPERTY_ELEMENT_EXCEPTIONS:
  338.             self.error("Invalid property element URI: %s" % name)
  339.         else:
  340.             current.predicate = absolutize(name)
  341.  
  342.         id = atts.get(RDF.ID, None)
  343.         if id is not None:
  344.             if not is_ncname(id):
  345.                 self.error("rdf:ID value is not a value NCName: %s" % id)
  346.             current.id = absolutize("#%s" % id)
  347.         else:
  348.             current.id = None
  349.  
  350.         resource = atts.get(RDF.resource, None)
  351.         nodeID = atts.get(RDF.nodeID, None)
  352.         parse_type = atts.get(RDF.parseType, None)
  353.         if resource is not None and nodeID is not None:
  354.             self.error("Property element cannot have both rdf:nodeID and rdf:resource")
  355.         if resource is not None:
  356.             object = absolutize(resource)
  357.             next.start = self.node_element_start
  358.             next.end = self.node_element_end
  359.         elif nodeID is not None:
  360.             if not is_ncname(nodeID):
  361.                 self.error("rdf:nodeID value is not a valid NCName: %s" % nodeID)
  362.             if self.preserve_bnode_ids is False:
  363.                 if nodeID in self.bnode:
  364.                     object = self.bnode[nodeID]
  365.                 else:
  366.                     subject = BNode()
  367.                     self.bnode[nodeID] = subject
  368.                     object = subject
  369.             else:
  370.                 object = subject = BNode(nodeID)
  371.             next.start = self.node_element_start
  372.             next.end = self.node_element_end
  373.         else:
  374.             if parse_type is not None:
  375.                 for att in atts:
  376.                     if att!=RDF.parseType and att!=RDF.ID:
  377.                         self.error("Property attr '%s' now allowed here" % att)
  378.                 if parse_type=="Resource":
  379.                     current.subject = object = BNode()
  380.                     current.char = self.property_element_char
  381.                     next.start = self.property_element_start
  382.                     next.end = self.property_element_end
  383.                 elif parse_type=="Collection":
  384.                     current.char = None
  385.                     object = current.list = RDF.nil #BNode()#self.parent.subject
  386.                     next.start = self.node_element_start
  387.                     next.end = self.list_node_element_end
  388.                 else: #if parse_type=="Literal":
  389.                      # All other values are treated as Literal
  390.                      # See: http://www.w3.org/TR/rdf-syntax-grammar/#parseTypeOtherPropertyElt
  391.                     object = Literal("", None, RDF.XMLLiteral)
  392.                     current.char = self.literal_element_char
  393.                     current.declared = {}
  394.                     next.start = self.literal_element_start
  395.                     next.char = self.literal_element_char
  396.                     next.end = self.literal_element_end
  397.                 current.object = object
  398.                 return
  399.             else:
  400.                 object = None
  401.                 current.char = self.property_element_char
  402.                 next.start = self.node_element_start
  403.                 next.end = self.node_element_end
  404.  
  405.         datatype = current.datatype = atts.get(RDF.datatype, None)
  406.         language = current.language
  407.         if datatype is not None:
  408.             # TODO: check that there are no atts other than datatype and id
  409.             datatype = absolutize(datatype)
  410.         else:
  411.             for att in atts:
  412.                 if not att.startswith(RDFNS):
  413.                     predicate = absolutize(att)
  414.                 elif att in PROPERTY_ELEMENT_ATTRIBUTES:
  415.                     continue
  416.                 elif att in PROPERTY_ATTRIBUTE_EXCEPTIONS:
  417.                     self.error("""Invalid property attribute URI: %s""" % att)
  418.                 else:
  419.                     predicate = absolutize(att)
  420.  
  421.                 if att==RDF.type:
  422.                     o = URIRef(atts[att])
  423.                 else:
  424.                     o = Literal(atts[att], language, datatype)
  425.  
  426.                 if object is None:
  427.                     object = BNode()
  428.                 self.store.add((object, predicate, o))
  429.         if object is None:
  430.             current.data = ""
  431.             current.object = None
  432.         else:
  433.             current.data = None
  434.             current.object = object
  435.  
  436.     def property_element_char(self, data):
  437.         current = self.current
  438.         if current.data is not None:
  439.             current.data += data
  440.  
  441.     def property_element_end(self, name, qname):
  442.         current = self.current
  443.         if current.data is not None and current.object is None:
  444.             current.object = Literal(current.data, current.language, current.datatype)
  445.             current.data = None
  446.         if self.next.end==self.list_node_element_end:
  447.             if current.object!=RDF.nil:
  448.                 self.store.add((current.list, RDF.rest, RDF.nil))
  449.         if current.object is not None:
  450.             self.store.add((self.parent.subject, current.predicate, current.object))
  451.             if current.id is not None:
  452.                 self.add_reified(current.id, (self.parent.subject,
  453.                                  current.predicate, current.object))
  454.         current.subject = None
  455.  
  456.     def list_node_element_end(self, name, qname):
  457.         current = self.current
  458.         if self.parent.list==RDF.nil:
  459.             list = BNode()
  460.             # Removed between 20030123 and 20030905
  461.             #self.store.add((list, RDF.type, LIST))
  462.             self.parent.list = list
  463.             self.store.add((self.parent.list, RDF.first, current.subject))
  464.             self.parent.object = list
  465.             self.parent.char = None
  466.         else:
  467.             list = BNode()
  468.             # Removed between 20030123 and 20030905
  469.             #self.store.add((list, RDF.type, LIST))
  470.             self.store.add((self.parent.list, RDF.rest, list))
  471.             self.store.add((list, RDF.first, current.subject))
  472.             self.parent.list = list
  473.  
  474.     def literal_element_start(self, name, qname, attrs):
  475.         current = self.current
  476.         self.next.start = self.literal_element_start
  477.         self.next.char = self.literal_element_char
  478.         self.next.end = self.literal_element_end
  479.         current.declared = self.parent.declared.copy()
  480.         if name[0]:
  481.             prefix = self._current_context[name[0]]
  482.             if prefix:
  483.                 current.object = "<%s:%s" % (prefix, name[1])
  484.             else:
  485.                 current.object = "<%s" % name[1]
  486.             if not name[0] in current.declared:
  487.                 current.declared[name[0]] = prefix
  488.                 if prefix:
  489.                     current.object += (' xmlns:%s="%s"' % (prefix, name[0]))
  490.                 else:
  491.                     current.object += (' xmlns="%s"' % name[0])
  492.         else:
  493.             current.object = "<%s" % name[1]
  494.  
  495.         for (name, value) in attrs.items():
  496.             if name[0]:
  497.                 if not name[0] in current.declared:
  498.                     current.declared[name[0]] = self._current_context[name[0]]
  499.                 name = current.declared[name[0]] + ":" + name[1]
  500.             else:
  501.                 name = name[1]
  502.             current.object += (' %s=%s' % (name, quoteattr(value)))
  503.         current.object += ">"
  504.  
  505.     def literal_element_char(self, data):
  506.         self.current.object += escape(data)
  507.  
  508.     def literal_element_end(self, name, qname):
  509.         if name[0]:
  510.             prefix = self._current_context[name[0]]
  511.             if prefix:
  512.                 end = u"</%s:%s>" % (prefix, name[1])
  513.             else:
  514.                 end = u"</%s>" % name[1]
  515.         else:
  516.             end = u"</%s>" % name[1]
  517.         self.parent.object += self.current.object + end
  518.