PyXML-0.8.2/ 0040755 0000764 0000144 00000000000 07614726124 011724 5 ustar martin users PyXML-0.8.2/demo/ 0040755 0000764 0000144 00000000000 07614726123 012647 5 ustar martin users PyXML-0.8.2/demo/dom/ 0040755 0000764 0000144 00000000000 07614726123 013426 5 ustar martin users PyXML-0.8.2/demo/dom/4tidy.py 0100644 0000764 0000144 00000001355 07413602737 015037 0 ustar martin users import sys, cStringIO
from xml.dom.ext.reader import HtmlLib
from xml.dom.ext import XHtmlPrint
def Tidy(doc):
#stream = cStringIO.StringIO()
#XHtmlPrint(doc, stream=stream)
#text = stream.getvalue()
XHtmlPrint(doc)
return
if __name__ == "__main__":
html_reader = HtmlLib.Reader()
if len(sys.argv) == 3:
uri = sys.argv[1]
encoding = sys.argv[2]
elif len(sys.argv) == 2:
uri = sys.argv[1]
encoding = ''
else:
print "%s requires one or two arguments: the first is a URL or file name to be tidied. The optional second is the encoding to assume for the input."%sys.argv[0]
sys.exit(-1)
html_doc = html_reader.fromUri(uri, charset=encoding)
Tidy(html_doc)
PyXML-0.8.2/demo/dom/README 0100644 0000764 0000144 00000007670 07244341241 014306 0 ustar martin users Example Programs and Demos for 4DOM.
====================================
Sample data files which can be used to exercise the various demos:
* addr_book1.xml
* addr_book2.xml
* book_catalog1.xml
* addr_book.dtd
* employee_table.html
Demos:
------
* dom_from_html_file.py
Demonstrates reading HTML from a file, and pretty-printing.
Example: "python dom_from_html_file.py employee_table.html"
* dom_from_xml_file.py
Demonstrates reading XML from a file, and pretty-printing. Try changing FromXml to have "validate=1".
Example: "python dom_from_xml_file.py addr_book1.xml"
* generate_html1.py
Demonstrates putting together a simple HTML page (a form in this case)
with the standard DOM factory interface.
Just execute with "python generate_html1.py"
You can re-direct the output to file and view the result with a browser. Try adding in more sophisticated form elements.
* generate_xml1.py
Demonstrates putting together a simple XML document with the standard DOM
factory interface.
Just execute with "python generate_xml1.py"
* 4tidy.py
Demonstrates the XHTML support in 4DOM. It takes a URL or file name on the
command line and reads the HTML source. It then prints xhtml based on the HTML
source to standard output.
try "python 4tidy.py http://fourthought.com"
* iterator1.py
Demonstrates the DOM standard Node Iterator interface. It iterates over each node in the read-in file, and prints out its node type and name. Then it iterates again, using the NodeFilter interface to restrict it to nodes of type Element.
Example: "python iterator1.py addr_book1.xml"
* visitor1.py
Demonstrates 4DOM's proprietary Walker/Visitor interface. If you only need to iterate over a tree in pre-order, you are advised to use the standard NodeIterator instead (see iterator1.py and xll_replace.py for examples). dom.ext.Visitor is best for defi
ning other iteration orders and rules.
This sample actually just runs through a pre-order walk, for simplicity. The output should be identical to that of the first part of iterator1.py.
Example: "python visitor1.py addr_book1.xml"
* trace_ns.py
A demo of 4DOM's namespace extensions. Given an XML file-name on the command line, it will walk through the elements in document order (using NodeIterator) and print out the default namespace in effect as well as those of the element and its attributes.
Example: "python trace_ns.py book_catalog1.xml"
For the Namespace spec, see
http://www.w3.org/TR/REC-xml-names/
For James Clark's excellent introduction to and clarification of namespaces, see
http://www.jclark.com/xml/xmlns.htm
* link_title_invert.py
Demonstrates node manipulations. It takes a sample document with anchors
embedded in header tags, and flips them so that the header tags are instead
embedded in the anchors.
just "python link_title_invert.py"
* xll_replace.py
A rather more involved demo. This program reads in an XML file, and looks for XLL-type hyperlinks (see http://www.oasis-open.org/cover/xll.html for information on this remarkably powerful spec).
Warning: This script uses a very obsolete version of XLink
When it finds such a link, it looks for the target XML doc
ument and parses it into a DOM node. It doesn't support XPointer for document fragments yet, but with a decent Xpointer processor, such as xptr (see below), you can add this yourself. It then replaces the node that contained the link with the entire con
tents of the target document of that link.
For a good example, look at addr_book1.xml and then addr_book2.xml. The former contains the following line:
if you run
"python xll_replace.py addr_book1.xml"
it will read in the addr_book2.xml file into a node, and replace the ENTRY-LINK node with the new one. It will then print out the result, which should be self-explanatory.
If you need help with the demos, or any other help working with 4DOM,
please don't hesistate to as on the mailing list: 4Suite@lists.fourthought.com.
PyXML-0.8.2/demo/dom/__init__.py 0100644 0000764 0000144 00000000270 07166146226 015535 0 ustar martin users ########################################################################
#
# File Name: __init__.py
#
# Documentation: http://docs.4suite.com/4DOM/__init__.py.html
#
PyXML-0.8.2/demo/dom/addr_book.dtd 0100644 0000764 0000144 00000000636 07117052117 016042 0 ustar martin users
PyXML-0.8.2/demo/dom/addr_book1.xml 0100644 0000764 0000144 00000001723 07117052117 016146 0 ustar martin users
Pieter Aaron
404 Error Way
404-555-1234404-555-4321404-555-5555pieter.aaron@inter.netEmeka Ndubuisi
42 Spam Blvd
767-555-7676767-555-7642800-SKY-PAGEx767676endubuisi@spamtron.comVasia Zhugenev
2000 Disaster Plaza
000-987-6543000-000-0000vxz@magog.ru
PyXML-0.8.2/demo/dom/addr_book2.xml 0100644 0000764 0000144 00000000430 07117052117 016141 0 ustar martin users
Gegbefuna Nwannem
666 Murtala Mohammed Blvd.
999-101-1001nwanneg@naija.ng
PyXML-0.8.2/demo/dom/benchmark.py 0100644 0000764 0000144 00000001717 07413602737 015736 0 ustar martin users # A DOM benchmark
import sys, time
from xml.dom import core, utils
def main():
global L, doc
if len(sys.argv) == 1:
print 'Usage: benchmark.py '
sys.exit()
filename = sys.argv[1]
file = open(filename, 'r')
size = len(file.read())
file.close()
print 'File %s is %iK in size' % (filename, size / 1024)
start_time = time.time()
doc = utils.FileReader( filename ).document
end_time = time.time()
print 'Building DOM tree:', end_time - start_time, 'sec'
# Convert DOM tree back to XML
start_time = time.time()
xml = doc.toxml()
end_time = time.time()
print 'Serializing back to XML:', end_time - start_time, 'sec'
# Time a complete getElementsByTagName()
start_time = time.time()
L = doc.getElementsByTagName("*")
end_time = time.time()
print 'getElementsByTagName("*"):', end_time - start_time, 'sec'
print L[0].nodeName
if __name__ == '__main__': main()
PyXML-0.8.2/demo/dom/book_catalog1.xml 0100644 0000764 0000144 00000000767 07117052117 016655 0 ustar martin users
Cheaper by the Dozen1568491379
This is a funny book!
PyXML-0.8.2/demo/dom/building.py 0100644 0000764 0000144 00000002577 07413602740 015600 0 ustar martin users # This demo converts a few nested objects into an XML representation,
# and provides a simple example of using the Builder class.
from xml.dom import core
from xml.dom.builder import Builder
import types, time
def object_convert(builder, obj):
# Put the entire object inside an element with the same name as
# the class.
builder.startElement( obj.__class__.__name__ )
L = obj.__dict__.keys()
L.sort()
for attr in obj.__dict__.keys():
# Skip internal attributes (ones that begin with a '_')
if attr[0] == '_': continue
value = getattr(obj, attr)
if type(value) == types.InstanceType:
# Recursively process subobjects
object_convert( builder, value)
else:
# Convert anything else to a string and put it in an element
builder.startElement(attr)
builder.text( str(value) )
builder.endElement(attr)
builder.endElement( obj.__class__.__name__ )
if __name__ == '__main__':
class Folder: pass
class Bookmark: pass
f=Folder()
f.title = "Folder Title"
f.createdTime = time.asctime( time.localtime( time.time() ) )
f.bookmark = b = Bookmark()
b.url, b.title = "http://www.python.org", "Python Home Page"
builder = Builder()
object_convert(builder, f)
print "Output from two nested objects:"
print builder.document.toxml()
PyXML-0.8.2/demo/dom/dom_from_html_file.py 0100644 0000764 0000144 00000001111 07413602740 017607 0 ustar martin users """Reads in an HTML file from the command line and pretty-prints it."""
from xml.dom.ext.reader import HtmlLib
from xml.dom import ext
def read_html_from_file(fileName):
#build a DOM tree from the file
reader = HtmlLib.Reader()
dom_object = reader.fromUri(fileName)
#strip any ignorable white-space in preparation for pretty-printing
ext.StripHtml(dom_object)
#pretty-print the node
ext.PrettyPrint(dom_object)
#reclaim the object
reader.releaseNode(dom_object);
if __name__ == '__main__':
import sys
read_html_from_file(sys.argv[1])
PyXML-0.8.2/demo/dom/dom_from_xml_file.py 0100644 0000764 0000144 00000000600 07244341241 017443 0 ustar martin users from xml.dom import ext
from xml.dom.ext.reader import PyExpat
def read_xml_from_file(fileName):
#build a DOM tree from the file
reader = PyExpat.Reader()
xml_dom_object = reader.fromUri(fileName)
ext.Print(xml_dom_object)
#reclaim the object
reader.releaseNode(xml_dom_object)
if __name__ == '__main__':
import sys
read_xml_from_file(sys.argv[1])
PyXML-0.8.2/demo/dom/domconv.py 0100644 0000764 0000144 00000004721 07413602740 015441 0 ustar martin users # A simple library to convert DOM object structures to SGML or XML output,
# usually for xml2html conversion.
import sys,types,string,StringIO
SKIP=1 # Ignore the element and its contents
STRIP=2 # Ignore the element, but process its contents
ID=3 # Identity transform
MAP=4 # Arg: (elem,hash). Map element to elem, map attrs using hash.
def escape_markup(str):
"""Takes a string and escapes all '<'s and quotes in it with character
entity references."""
str=string.replace(str,"<","<")
return string.replace(str,'"',""")
def convert(rootnode,spec,writer=sys.stdout):
"""Takes a DOM node, a conversion specification and a file-like object
to write the converted data to, and performs the actual conversion.
The spec hashtable must map element names to (action,arg) tuples, where
action must be one of the constants at the top of this file. arg is only
used for MAP, where it must be a tuple (elementname,maphash) where the
elementname is the name of the element to substitute for the original
one, and maphash is a hashtable that maps attribute names to either the
attribute name to substitute or a function that takes the attribute value
and returns the string to replace the entire attr='val' sequence with.
"""
try:
(action,arg)=spec[rootnode.GI]
except KeyError:
action=STRIP
if action==SKIP:
return
elif action==STRIP:
pass
elif action==ID:
writer.write("<" + rootnode.GI)
for (name,val) in rootnode.attributes.items():
writer.write(" %s='%s'" % (name,escape_markup(val)))
writer.write(">")
elif action==MAP:
writer.write("<" + arg[0])
for (name,val) in rootnode.attributes.items():
if arg[1].has_key(name):
map=arg[1][name]
if type(map)==types.StringType:
writer.write(" %s=\"%s\"" % (map,escape_markup(val)))
else:
writer.write(map(escape_markup(val)))
writer.write(">")
for child in rootnode.getChildren():
if child.GI=="#PCDATA":
writer.write(escape_markup(child.data))
else:
convert(child,spec,writer)
if action==ID:
writer.write("%s>" % rootnode.GI)
elif action==MAP:
writer.write("%s>" % arg[0])
def convert_str(rootnode,spec):
obj=StringIO.StringIO()
convert(rootnode,spec,obj)
return obj.getvalue()
PyXML-0.8.2/demo/dom/employee_table.html 0100644 0000764 0000144 00000002322 07244341241 017267 0 ustar martin users
FourThought Employee List
PyXML-0.8.2/demo/dom/generate_html1.py 0100644 0000764 0000144 00000003050 07413602740 016665 0 ustar martin users """
A basic example of using the DOM to create an HTML document from scratch.
Also demonstrates creation of HTML forms
"""
from xml.dom import ext
from xml.dom import implementation
if __name__ == '__main__':
#create a concrete HTMLDocument instance.
doc = implementation.createHTMLDocument('A Basic HTML Document')
#add in body
doc.body = doc.createElement('Body')
#Create a form
form = doc.createElement('Form')
#Create some text. Note: every character is represented in some
#DOM object. All text (even between tags) is in a text node
t = doc.createTextNode('Employee Name:')
#Create an input tag
i = doc.createElement('Input')
#All elements can have attributes directly set
i.setAttribute('TYPE','TEXT')
#Some have helper functions defined.
#This one sets the SIZE attribute to 20
#Note that the argument must be a string. 4DOM closely
#follows the DOM spec for the type of the arguments, even
#when the spec is inconsistent or counter-intuitive
i.size = '20'
#This sets the NAME attribute
i.name = 'EmployeeName'
#Set the form's ACTION attribute
form.action = '/cgi-local/test.py'
#this inserts i as the last child in the form
form.appendChild(i)
#Insert t before i in form's child list
form.insertBefore(t,i)
#add the form to the document's body. Note that you can't
#add child elements directly to the document.
doc.body.appendChild(form)
#This prints out the text representation of the HTML document
ext.PrettyPrint(doc)
PyXML-0.8.2/demo/dom/generate_xml1.py 0100644 0000764 0000144 00000002222 07413602740 016521 0 ustar martin users """
A basic example of using the DOM to create an XML document from scratch.
"""
from xml.dom import ext
from xml.dom import implementation
if __name__ == '__main__':
#Create a doctype using document type name, sysid and pubid
dt = implementation.createDocumentType('mydoc', '', '')
#Create a document using document element namespace URI, doc element
#name and doctype. This automatically creates a document element
#which is the single element child of the document
doc = implementation.createHTMLDocument('', 'mydoc', dt)
#Get the document element
doc_elem = doc.documentElement
#Create an element: the Document instanmce acts as a factory
new_elem = doc.createElementNS('', 'spam')
#Create an attribute on the new element
new_elem.setAttributeNS('', 'eggs', 'sunnysideup')
#Create a text node
new_text = doc.createTextNode('some text here...')
#Add the new text node to the new element
new_elem.appendChild(new_text)
#Add the new element to the document element
doc_elem.appendChild(new_elem)
#Print out the resulting document
import xml.doc.ext
xml.doc.ext.Print(doc)
PyXML-0.8.2/demo/dom/html2html 0100755 0000764 0000144 00000003557 06624412225 015271 0 ustar martin users #!/usr/bin/python
#
# This example program converts a chunk of HTML to a DOM tree.
# It then prints the tree as HTML, as XML, and it prints a list of all
# the hyperlinks in the document by using getElementsByTagName() to
# retrieve all the A elements.
from xml.dom.html_builder import HtmlBuilder
from xml.dom.writer import HtmlWriter
from xml.dom import core
HTML_DATA = """
Les HOWTO Linux
Les HOWTO Linux
Les Howto que vous trouverez ci-dessous sont en français.
Ils peuvent etre trouvés dans les formats suivants
sur le site
ftp.lip6.fr
dans le répertoire /pub/linux/french/docs/HOWTO :
"""
# Construct an HtmlBuilder object and feed the data to it
b = HtmlBuilder()
b.feed(HTML_DATA)
# Get the newly-constructed document object
doc = b.document
# Output it as HTML
print "============"
print "HTML version"
w = HtmlWriter()
w.write(b.document)
# Output it as XML
print "\n==========="
print "XML version"
print doc.toxml()
print "\n==========="
print "Links in the document"
# Retrieve all the link objects
links = doc.getElementsByTagName('A')
for node in links:
# Collect any children of the A element that are Text nodes
# (Note that this won't work on invalid HTML, like
# Text. You could fix this by actually
# traversing all the child nodes of the A element.)
linktext = ""
for child in node.childNodes:
if child.nodeType == core.TEXT_NODE:
linktext = linktext + child.value
# Get the HREF attribute, if present
url = node.getAttribute('HREF')
if url != "":
print "HREF=", url, linktext
print links
PyXML-0.8.2/demo/dom/iterator1.py 0100644 0000764 0000144 00000001721 07413602740 015703 0 ustar martin users """Demonstrates basic walking using DOM level 2 iterators"""
from xml.dom.ext.reader import PyExpat
from xml.dom.NodeFilter import NodeFilter
def Iterate(xml_dom_object):
print "Printing all nodes:"
nit = xml_dom_object.ownerDocument.createNodeIterator(xml_dom_object, NodeFilter.SHOW_ALL, None, 0)
curr_node = nit.nextNode()
while curr_node:
print "%s node %s\n"%(curr_node.nodeType, curr_node.nodeName)
curr_node = nit.nextNode()
print "\n\n\nPrinting only element nodes:"
snit = xml_dom_object.ownerDocument.createNodeIterator(xml_dom_object, NodeFilter.SHOW_ELEMENT, None, 0)
curr_node = snit.nextNode()
while curr_node:
print "%s node %s\n"%(curr_node.nodeType, curr_node.nodeName)
curr_node = snit.nextNode()
if __name__ == '__main__':
import sys
reader = PyExpat.Reader()
xml_dom_object = reader.fromUri(sys.argv[1])
Iterate(xml_dom_object)
reader.releaseNode(xml_dom_object)
PyXML-0.8.2/demo/dom/link_title_invert.py 0100644 0000764 0000144 00000002272 07413602740 017520 0 ustar martin users from xml.dom import Node, ext
from xml.dom.ext.reader import PyExpat
test_doc = """
LADIES
Memnon, Memnon, that lady...
"""
def link_title_invert():
#build a DOM tree from the file
reader = PyExpat.Reader()
doc = reader.fromString(test_doc)
h2_elements = doc.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'h2')
for e in h2_elements:
parent = e.parentNode
a_list = filter(lambda x: (x.nodeType == Node.ELEMENT_NODE) and (x.localName == 'a'), e.childNodes)
a = a_list[0]
e.removeChild(a)
for node in a.childNodes:
#Automatically also removes the child from a
e.appendChild(node)
parent.replaceChild(a, e)
a.appendChild(e)
ext.Print(doc)
#reclaim the object; not necessary with Python 2.0
reader.releaseNode(doc)
if __name__ == '__main__':
import sys
link_title_invert()
PyXML-0.8.2/demo/dom/trace_ns.py 0100644 0000764 0000144 00000002231 07413602740 015564 0 ustar martin users '''
Walk through a namespace-compliant XML file and print out the
the namespaces of all elements and attributes in document order
'''
from xml.dom.ext.reader import PyExpat
from xml.dom.NodeFilter import NodeFilter
def TraceNs(doc):
snit = doc.createNodeIterator(doc, NodeFilter.SHOW_ELEMENT, None, 0)
curr_elem = snit.nextNode()
while curr_elem:
print "Current Element", curr_elem.nodeName
#FIXME: put a GetDefaultNs method into Ext
#ns = Namespace.GetDefaultNs(curr_elem)
#print "\tDefault NS\t", ns
print "\t"+curr_elem.nodeName+"\t\t", curr_elem.namespaceURI
header_printed = 0
for k in curr_elem.attributes.keys():
if curr_elem.attributes[k].namespaceURI:
if not header_printed:
header_printed = 1
print "\tAttributes"
print "\t\t"+curr_elem.attributes[k].nodeName+"\t", curr_elem.attributes[k].namespaceURI
print
curr_elem = snit.nextNode()
if __name__ == "__main__":
import sys
reader = PyExpat.Reader()
doc = reader.fromUri(sys.argv[1])
TraceNs(doc)
reader.releaseNode(doc)
PyXML-0.8.2/demo/dom/visitor1.py 0100644 0000764 0000144 00000002355 07413602740 015555 0 ustar martin users """Demonstrates basic, pre-order DOM walking using the default, bare-bones visitor"""
from xml.dom.ext.reader import PyExpat
from xml.dom import Node
from xml.dom.ext import Visitor
from xml.dom.ext.reader import Sax2
from xml.dom.ext import ReleaseNode
class NsVisitor(Visitor.Visitor):
def visit(self, node):
print "Node %s namespaceURI: '%s' qualified name: '%s' localName: '%s' prefix: '%s'\n"%(str(node), node.namespaceURI, node.nodeName, node.localName, node.prefix)
if node.nodeType == Node.ELEMENT_NODE:
for k in node.attributes.keys():
print "Node %s namespaceURI: '%s' qualified name: '%s' localName: '%s' prefix: '%s'\n"%(str(node.attributes[k]), node.attributes[k].namespaceURI, node.attributes[k].nodeName, node.attributes[k].localName, node.attributes[k].prefix)
return None
def Walk(xml_dom_object):
visitor = Visitor.Visitor()
walker = Visitor.Walker(visitor, xml_dom_object)
walker.run()
visitor = NsVisitor()
walker = Visitor.Walker(visitor, xml_dom_object)
walker.run()
if __name__ == '__main__':
import sys
reader = PyExpat.Reader()
xml_dom_object = reader.fromUri(sys.argv[1])
Walk(xml_dom_object)
reader.releaseNode(xml_dom_object)
PyXML-0.8.2/demo/dom/xll_replace.py 0100644 0000764 0000144 00000003716 07413602740 016271 0 ustar martin users """
Demonstrates some advanced DOM manipulation.
This function looks for simple XLinks and replaces the node containing
such links with the contents of the referenced document.
"""
from xml.dom import Node
from xml.dom.NodeFilter import NodeFilter
from xml.dom import ext
from xml.dom.ext.reader import PyExpat
def XllReplace(start_node):
reader = PyExpat.Reader()
owner_doc = start_node.ownerDocument
snit = owner_doc.createNodeIterator(start_node, NodeFilter.SHOW_ELEMENT, None, 0)
curr_node = snit.nextNode()
while curr_node:
#Only empty nodes are allowed to have Links
if not curr_node.childNodes.length and curr_node.attributes:
is_link = 0
href = None
for k in curr_node.attributes.keys():
if (curr_node.attributes[k].localName, curr_node.attributes[k].namespaceURI) == ("link", "http://www.w3.org/XML/XLink/0.9"):
is_link = 1
elif (curr_node.attributes[k].localName, curr_node.attributes[k].namespaceURI) == ("href", "http://www.w3.org/XML/XLink/0.9"):
href = curr_node.attributes[k].value
if is_link and href:
#Then make a tree of the new file and insert it
f = open(href, "r")
st = f.read()
new_df = reader.fromString(st, ownerDoc=start_node.ownerDocument)
#Get the first element node and assume it's the document node
for a_node in new_df.childNodes:
if a_node.nodeType == Node.ELEMENT_NODE:
doc_root = a_node
break
curr_node.parentNode.replaceChild(doc_root, curr_node)
curr_node = snit.nextNode()
return start_node
if __name__ == "__main__":
import sys
reader = PyExpat.Reader()
xml_dom_tree = reader.fromUri(sys.argv[1])
XllReplace(xml_dom_tree)
ext.PrettyPrint(xml_dom_tree)
reader.releaseNode(xml_dom_tree)
PyXML-0.8.2/demo/dom/xpointer_query.py 0100644 0000764 0000144 00000001211 07413602740 017060 0 ustar martin users """Demonstrates using the xptr.py tool to query DOM Nodes using the XPointer spec"""
from xml.dom import ext
from xml.dom.ext.reader import Sax2
import xptr
if __name__ == '__main__':
import sys
xpointer_expr = sys.argv[1]
try:
xml_dom_object = Sax2.FromXmlUrl(sys.argv[2], validate=0)
except Sax.saxlib.SAXException, msg:
print "SAXException caught:", msg
except Sax.saxlib.SAXParseException, msg:
print "SAXParseException caught:", msg
result_node = xptr.LocateNode(xml_dom_object, xpointer_expr)
ext.StripXml(result_node)
ext.PrettyPrint(result_node)
ext.ReleaseNode(result_node)
PyXML-0.8.2/demo/dom/xptr.py 0100644 0000764 0000144 00000043763 07413602740 015002 0 ustar martin users """
This is an experimental implementation of the XPointer locator language.
Version 0.20 - 23.Aug.98
Lars Marius Garshol - larsga@ifi.uio.no
http://www.stud.ifi.uio.no/~larsga/download/python/xml/xptr.html
Changes since version 0.10:
- 'id' locator term implemented
- 'attr' locator term implemented
- node type qualifiers implemented
- 'origin' locator term implemented
Modified by Uche Ogbuji 25.Jan.99 to work with 4DOM.
Modified by Uche Ogbuji 18.Nov.99 to work with the emerging Python/DOM binding 4DOM. Distributed with permission.
"""
import re,string,sys
from xml.dom import Node
from xml.dom import ext
# Spec deviations:
# - html keyword not supported
# - negative instance numbers not supported
# - #cdata node type selector not supported
# - * for attribute values/names not supported
# - preceding keyword not supported
# - span keyword unsupported
# - support 'string' location terms
# Spec questions
# - what if locator fails?
# - what to do with "span(...).child(1)"?
# - how to continue from a set of selected nodes?
# - attr: error if does not use element as source?
# - should distinguish between semantic errors and failures?
# - can string terms locate inside attr vals?
# - are the string loc semantics a bit extreme? perhaps restrict to one node?
# - how to represent span and string results in terms of the DOM?
# Global variables
version="0.20"
specver="WD-xptr-19980303"
# Useful regular expressions
reg_sym=re.compile("[a-z]+|\\(|\\)|\\.|[-+]?[1-9][0-9]*|[A-Za-z_:][\-A-Za-z_:.0-9]*|,|#[a-z]+|\\*|\"[^\"]*\"|'[^']*'")
reg_sym_param=re.compile(",|\)|\"|'")
reg_name=re.compile("[A-Za-z_:][\-A-Za-z_:.0-9]*")
# Some exceptions
class XPointerException(Exception):
"Means something went wrong when attempting to follow an XPointer."
pass
class XPointerParseException(XPointerException):
"Means the XPointer was syntactically invalid."
def __init__(self,msg,pos):
self.__msg=msg
self.__pos=pos
def get_pos(self):
return self.__pos
def __str__(self):
return self.__msg % self.__pos
class XPointerFailedException(XPointerException):
"Means the XPointer was logically invalid."
pass
class XPointerUnsupportedException(XPointerException):
"Means the XPointer used unsupported constructs."
pass
# Simple XPointer lexical analyzer
class SymbolGenerator:
"Chops XPointers up into distinct symbols."
def __init__(self,xpointer):
self.__data=xpointer
self.__pos=0
self.__last_was_param=0
self.__next_is=""
def get_pos(self):
"Returns the current position in the string."
return self.__pos
def more_symbols(self):
"True if there are more symbols in the XPointer."
return self.__pos1:
type=params[1]
if not (type=="#element" or type=="#pi" or type=="#comment" or \
type=="#text" or type=="#cdata" or type=="#all" or \
self.__is_valid(type,reg_name)):
raise XPointerParseException("Invalid type at %s",
self.__sgen.get_pos())
else:
type="#element"
attrs=[]
ix=2
while ix+11:
skiplit=params[1]
else:
skiplit=None
if len(params)>2:
if params[2]=="end":
pos="end"
else:
try:
pos=int(params[2])
except ValueError,e:
raise XPointerParseException("Expected number at %s",
self.__sgen.get_pos())
if pos==0:
raise XPointerParseException("0 is not an acceptable "
"value at %s",
self.__sgen.get_pos())
else:
pos=None
if len(params)>3:
try:
length=int(params[3])
except ValueError,e:
raise XPointerParseException("Expected number at %s",
self.__sgen.get_pos())
else:
length=0
self.handle_string_term(no,skiplit,pos,length)
# Event methods to be overridden
def handle_abs_term(self,name,param):
"Called to handle absolute location terms."
pass
def handle_rel_term(self,name,no,type,attrs):
"Called to handle relative location terms."
pass
def handle_attr_term(self,attr_name):
"Called to handle 'attr' location terms."
pass
def handle_span_term(self,frm,to):
"Called to handle 'span' location terms."
pass
def handle_string_term(self,no,skiplit,pos,length):
"Called to handle 'string' location terms."
pass
# ----- XPointer implementation that navigates a DOM tree
# Iterator classes
class DescendantIterator:
def __init__(self):
self.stack=[]
def __call__(self,node):
next=node.firstChild
if next==None:
next=node.nextSibling
while next==None:
if self.stack==[]:
raise XPointerFailedException("No matching node")
next=self.stack[-1].nextSibling
del self.stack[-1]
self.stack.append(next)
return next
class FollowingIterator:
def __init__(self):
self.seen_hash={}
self.skip_child=0
def __call__(self,node):
if not self.skip_child:
next=node.firstChild
else:
self.skip_child=0
next=None
if next==None:
next=node.getNextSibling()
if next==None:
next=node.parentNode
self.skip_child=1 # Don't go down, we've been there :-)
if next.GI=="#DOCUMENT":
raise XPointerFailedException("No matching node")
if self.seen_hash.has_key(next.id()):
next=node.nextSibling
prev=node
while next==None:
next=prev.parentNode
self.skip_child=1 # Don't go down, we've been there :-)
prev=next
if next.nodeName=="#DOCUMENT":
raise XPointerFailedException("No matching node")
if self.seen_hash.has_key(next.id()):
next=prev.nextSibling
if next!=None:
self.skip_child=0
else:
# We're above all the nodes we've looked at. Throw out the
# hashed objects.
self.seen_hash.clear()
self.seen_hash[next.id()]=1
return next
# The implementation itself
class XDOMLocator(XPointerParser):
def __init__(self, xpointer, document):
XPointerParser.__init__(self, xpointer)
self.__node=document
self.__first=1
self.__prev=None
def __node_matches(self,node,type,attrs):
"Checks whether a DOM node matches a foo(2,SECTION,ID,I5) selector."
if type==node.nodeName or \
(type=="#element" and node.nodeType == Node.ELEMENT_NODE) or \
(type=="#pi" and node.nodeType == Node.PROCESSING_INSTRUCTION_NODE) or \
(type=="#comment" and node.nodeType == Node.COMMENT_NODE) or \
(type=="#text" and node.nodeType == Node.TEXT_NODE) or \
(type=="#cdata" and node.nodeType == Node.CDATA_SECTION_NODE) or \
type=="#all":
if attrs!=None:
for (a,v) in attrs:
try:
if v!=node.getAttribute(a):
return 0
except KeyError,e:
return 0
return 1
else:
return 0
def __get_node(self,no,type,attrs,iterator):
"""General method that iterates through the tree calling the iterator
on the current node for each step to get the next node."""
count=0
current=iterator(self.__node)
while current!=None:
if self.__node_matches(current,type,attrs):
count=count+1
if count==no:
return current
current=iterator(current)
raise XPointerFailedException("No matching node")
def __get_child(self,no,type,attrs):
if type==None:
candidates = self.__node.childNodes
else:
candidates = []
for obj in self.__node.childNodes:
if self.__node_matches(obj,type,attrs):
candidates.append(obj)
try:
return candidates[no-1]
except IndexError,e:
raise XPointerFailedException("No matching node")
def get_node(self):
"Returns the located node."
return self.__node
def handle_abs_term(self,name,param):
"Called to handle absolute location terms."
if name=="root":
if self.__node.nodeType != Node.DOCUMENT_NODE:
raise XPointerFailedException("Expected document node")
self.__node=self.__node.documentElement
elif name=="origin":
pass # Just work from current node
elif name=="id":
self.__node=ext.GetElementById(self.__node, param)
elif name=="html":
raise XPointerUnsupportedException("Term type 'html' unsupported.")
def handle_rel_term(self,name,no,type,attrs):
"Called to handle relative location terms."
if name=="child":
next=self.__get_child(no,type,attrs)
elif name=="ancestor":
next=self.__get_node(no,type,attrs,DOM.Node._get_parentNode)
elif name=="psibling":
next=self.__get_node(no,type,attrs,DOM.Node._get_previousSibling)
elif name=="fsibling":
next=self.__get_node(no,type,attrs,DOM.Node._get_nextSibling)
elif name=="descendant":
next=self.__get_node(no,type,attrs,DescendantIterator())
elif name=="following":
next=self.__get_node(no,type,attrs,FollowingIterator())
self.__node=next
self.__prev=name
def handle_attr_term(self, attr_name):
if __node.nodeType != Node.ELEMENT_NODE:
raise XPointerFailedException("'attr' location term used from "
"non-element node")
if not self.__node.attributes.has_key(attr_name):
raise XPointerFailedException("Non-existent attribute '%s' located"
" by 'attr' term" % attr_name)
self.__node=self.__node.attributes.getNamedItem(attr_name)
def handle_string_term(self,no,skiplit,pos,length):
raise XPointerUnsupportedException("'string' location terms not "
"supported")
def LocateNode(node, xpointer):
try:
xp=XDOMLocator(xpointer, node)
xp.parse()
return xp.get_node()
except XPointerParseException,e:
print "ERROR: "+str(e)
PyXML-0.8.2/demo/genxml/ 0040755 0000764 0000144 00000000000 07614726123 014141 5 ustar martin users PyXML-0.8.2/demo/genxml/README 0100644 0000764 0000144 00000002423 07001374222 015004 0 ustar martin users This example demonstrates how to generate XML from non-XML data
sources. This example is based directly on an example presented by
Tom Gavin and Joseph E. Hughes at the August 1999 Washington DC
SGML/XML User's Group meeting. PowerPoint slides containing the
original DOM-based solution in Java are available at
http://www.eccnet.com/sgmlug/.
Since the specifics of reading other data formats vary greatly, this
example will use a simple comma-separated-value format similar to that
found as an "export" format for many applications which work with
tabular data. A sample data file is contained in data.txt.
The loaddata.py script demonstrates three different approaches to XML
generation: DOM-based, SAX-based, and .write()-based. The first
two approaches are specific to generating XML, while the third could
be used to generate any format. It is interesting to note the
differences in code size to get roughly the same output using each of
the three approaches.
The script's main() function does little but parse the command line,
selecting the processing class appropriately. Processing consists of
instantiating the processing class and calling its run() method.
Concrete subclasses of the abstract processing class determine the
actual machinery used to create the XML output.
PyXML-0.8.2/demo/genxml/data.txt 0100644 0000764 0000144 00000000124 07001374222 015572 0 ustar martin users lname,fname,emp,manager
Jones,Tom,1111,1111
Smith,John,2222,1111
Doe,Jane,3333,1111
PyXML-0.8.2/demo/genxml/loaddata.py 0100644 0000764 0000144 00000017627 07165177650 016304 0 ustar martin users #! /usr/bin/env python
"""
%(program)s -- example script to convert comma-separated value file to
XML using the Document Object Model (DOM), the Simple
API for XML (SAX), or the 'write' model (a bunch of calls
to .write()).
Usage: %(program)s [--dom|--sax|--write] [infile [outfile]]
"""
__version__ = '$Revision: 1.3 $'
import getopt
import os
import string
import sys
# Note that we only need one of these for any given version of the
# processing class.
#
from xml.dom.DOMImplementation import implementation
import xml.sax.writer
import xml.utils
def main():
"""Process command line parameters and run the conversion."""
inpath = "-"
outpath = "-"
args = sys.argv[1:]
processor_class = DOMProcess
try:
opts, args = getopt.getopt(args, "dhsw",
["dom", "help", "sax", "write"])
except getopt.error, e:
usage(err=e, rc=2)
for opt, arg in opts:
if opt in ("-d", "--dom"):
processor_class = DOMProcess
elif opt in ("-h", "--help"):
usage()
elif opt in ("-s", "--sax"):
processor_class = SAXProcess
elif opt in ("-w", "--write"):
processor_class = WriteProcess
if len(args) == 2:
inpath, outpath = args
elif len(args) == 1:
inpath = args[0]
elif len(args) == 0:
pass
else:
usage(err="too many command-line arguments", rc=2)
infp = get_input(inpath)
outfp = get_output(outpath)
processor = processor_class(infp, outfp)
processor.run()
infp.close()
outfp.close()
class BaseProcess:
"""Base class for the conversion processors. Each concrete subclass
must provide the following methods:
initOutput()
Initialize the output stream and any internal data structures
that the conversion process needs.
addRecord(lname, fname, type)
Add one record to the output stream (or the internal structures)
where lname is the last name, fname is the first name, and type
is either 'manager' or 'employee'.
finishOutput()
Finish all output generation. If all work has been on internal
data structures, this is where they should be converted to text
and written out.
"""
def __init__(self, infp, outfp):
"""Store the input and output streams for later use."""
self.infp = infp
self.outfp = outfp
def run(self):
"""Perform the complete conversion process.
This method is responsible for parsing the input and calling the
subclass-provided methods in the right order.
"""
self.initOutput()
self.infp.readline() # ignore field names
rec = self.getNextRecord()
while rec:
lname, fname, type = rec
self.addRecord(lname, fname, type)
rec = self.getNextRecord()
self.finishOutput()
def getNextRecord(self):
"""Read and return the next input record, or return None."""
line = self.infp.readline()
if line:
parts = map(string.strip, string.split(line, ','))
lname, fname, eid, mid = parts
type = ("employee", "manager")[eid == mid]
return lname, fname, type
else:
return None
class DOMProcess(BaseProcess):
"""Concrete conversion process which uses a DOM structure as an
internal data structure.
Content is added to the DOM tree for each input record, and the
entire tree is serialized and written to the output stream in the
finishOutput() method.
"""
def initOutput(self):
# Create a new document with no namespace uri, qualified name,
# or document type
self.document = implementation.createDocument(None,None,None)
self.personnel = self.document.createElement("personnel")
self.document.appendChild(self.personnel)
def addRecord(self, lname, fname, type):
doc = self.document
self.personnel.appendChild(doc.createTextNode("\n "))
emp = doc.createElement("employee")
emp.setAttribute("type", type)
self.personnel.appendChild(emp)
emp.appendChild(doc.createTextNode("\n "))
ln = doc.createElement("lname")
ln.appendChild(doc.createTextNode(lname))
emp.appendChild(ln)
emp.appendChild(doc.createTextNode("\n "))
fn = doc.createElement("fname")
fn.appendChild(doc.createTextNode(fname))
emp.appendChild(fn)
emp.appendChild(doc.createTextNode("\n "))
def finishOutput(self):
t = self.document.createTextNode("\n")
self.personnel.appendChild(t)
# XXX toxml not supported by 4DOM
# self.outfp.write(self.document.toxml())
xml.dom.ext.PrettyPrint(self.document, self.outfp)
self.outfp.write("\n")
class SAXProcess(BaseProcess):
"""Concrete conversion process that uses a SAX implementation that
writes output to a file.
XML is generated by calling the SAX methods that would be called
when the resulting document instance is parsed. Data is written to
the output stream incrementally with this approach, and no real
internal state is maintained.
"""
def initOutput(self):
info = xml.sax.writer.XMLDoctypeInfo()
info.add_element_container("personnel")
info.add_element_container("employee")
saxout = self.saxout = xml.sax.writer.PrettyPrinter(
self.outfp, dtdinfo=info)
saxout.startDocument()
saxout.startElement("personnel", {})
def addRecord(self, lname, fname, type):
saxout = self.saxout
saxout.startElement("employee", {"type": type})
saxout.startElement("lname", {})
saxout.characters(lname, 0, len(lname))
saxout.endElement("lname")
saxout.startElement("fname", {})
saxout.characters(fname, 0, len(fname))
saxout.endElement("fname")
saxout.endElement("employee")
def finishOutput(self):
self.saxout.endElement("personnel")
self.saxout.endDocument()
class WriteProcess(BaseProcess):
"""Concrete conversion process that simply formats the XML
directly and uses the write() method of a file to write it out.
The only helper function used to generate the XML is the
xml.utils.escape() function; the methods of this class are
solely responsible for proper formatting of the markup.
"""
#
# Note the simplicity of using a bunch of write() calls; using print
# statements would also be reasonable in many contexts.
#
def initOutput(self):
self.outfp.write('\n')
self.outfp.write("\n")
def addRecord(self, lname, fname, type):
self.outfp.write(' \n' % type)
self.outfp.write(" %s\n" % xml.utils.escape(lname))
self.outfp.write(" %s\n" % xml.utils.escape(fname))
self.outfp.write(" \n")
def finishOutput(self):
self.outfp.write("\n")
def get_input(path):
"""Get input file from path; '-' indicates stdin."""
if path == "-":
return sys.stdin
else:
return open(path)
def get_output(path):
"""Get output file from path; '-' indicates stdout."""
if path == "-":
return sys.stdout
else:
return open(path, "w")
def usage(err=None, rc=0):
"""Write out a usage message, possibly to stderr.
If err or rc are true, the message is written to stderr instead of
stdout. The script docstring is used as the source of help text.
Exits with result code rc.
"""
if err or rc:
sys.stdout = sys.stderr
program = os.path.basename(sys.argv[0])
if err:
print "%s: %s" % (program, str(err))
vars = {"program": program}
print __doc__ % vars
sys.exit(rc)
if __name__ == "__main__":
main()
PyXML-0.8.2/demo/quotes/ 0040755 0000764 0000144 00000000000 07614726123 014167 5 ustar martin users PyXML-0.8.2/demo/quotes/README 0100644 0000764 0000144 00000001636 07175443715 015057 0 ustar martin users The files in this directory demonstrate maintaining a quotation
collection in XML. The still-unnamed markup language contains
'quotation' elements, which contain the text of the quotation and
optional 'author' and 'source' elements. For the quotation text,
there are some simple semantic markups such as 'em', 'cite', and
'foreign'.
quotations.dtd DTD for the markup language.
sample.xml A sample quotation file.
qtfmt.py Program to read a file marked up using the language
specified in quotations.dtd, and output the
list in HTML, text, or fortune format.
The qtfmt.py script requires Python 2.0, since it assumes UTF-8 output
and uses the codecs module to convert its output to Latin-1.
Contact amk1@bigfoot.com if you have questions or comments about the
contents of this directory. For the author's complete quotation
collections, please go to http://starship.python.net/crew/amk/quotations/
PyXML-0.8.2/demo/quotes/qtfmt.py 0100644 0000764 0000144 00000033110 07413602740 015662 0 ustar martin users #!/usr/bin/env python
#
# qtfmt.py v1.10
# v1.10 : Updated to use Python 2.0 Unicode type.
#
# Read a document in the quotation DTD, converting it to a list of Quotation
# objects. The list can then be output in several formats.
__doc__ = """Usage: qtfmt.py [options] file1.xml file2.xml ...
If no filenames are provided, standard input will be read.
Available options:
-f or --fortune Produce output for the fortune(1) program
-h or --html Produce HTML output
-t or --text Produce plain text output
-m N or --max N Suppress quotations longer than N lines;
defaults to 0, which suppresses no quotations at all.
"""
import string, re, cgi, types
import codecs
from xml.sax import saxlib, saxexts
def simplify(t, indent="", width=79):
"""Strip out redundant spaces, and insert newlines to
wrap the text at the given width."""
t = string.strip(t)
t = re.sub('\s+', " ", t)
if t=="": return t
t = indent + t
t2 = ""
while len(t) > width:
index = string.rfind(t, ' ', 0, width)
if index == -1: t2 = t2 + t[:width] ; t = t[width:]
else: t2 = t2 + t[:index] ; t = t[index+1:]
t2 = t2 + '\n'
return t2 + t
class Quotation:
"""Encapsulates a single quotation.
Attributes:
stack -- used during construction and then deleted
text -- A list of Text() instances, or subclasses of Text(),
containing the text of the quotation.
source -- A list of Text() instances, or subclasses of Text(),
containing the source of the quotation. (Optional)
author -- A list of Text() instances, or subclasses of Text(),
containing the author of the quotation. (Optional)
Methods:
as_fortune() -- return the quotation formatted for fortune
as_html() -- return an HTML version of the quotation
as_text() -- return a plain text version of the quotation
"""
def __init__(self):
self.stack = [ Text() ]
self.text = []
def as_text(self):
"Convert instance into a pure text form"
output = ""
def flatten(textobj):
"Flatten a list of subclasses of Text into a list of paragraphs"
if type(textobj) != types.ListType: textlist=[textobj]
else: textlist = textobj
paragraph = "" ; paralist = []
for t in textlist:
if (isinstance(t, PreformattedText) or
isinstance(t, CodeFormattedText) ):
paralist.append(paragraph)
paragraph = ""
paralist.append(t)
elif isinstance(t, Break):
paragraph = paragraph + t.as_text()
paralist.append(paragraph)
paragraph = ""
else:
paragraph = paragraph + t.as_text()
paralist.append(paragraph)
return paralist
# Flatten the list of instances into a list of paragraphs
paralist = flatten(self.text)
if len(paralist) > 1:
indent = 2*" "
else:
indent = ""
for para in paralist:
if isinstance(para, PreformattedText) or isinstance(para, CodeFormattedText):
output = output + para.as_text()
else:
output = output + simplify(para, indent) + '\n'
attr = ""
for i in ['author', 'source']:
if hasattr(self, i):
paralist = flatten(getattr(self, i))
text = string.join(paralist)
if attr:
attr = attr + ', '
text = string.lower(text[:1]) + text[1:]
attr = attr + text
attr=simplify(attr, width = 79 - 4 - 3)
if attr: output = output + ' -- '+re.sub('\n', '\n ', attr)
return output + '\n'
def as_fortune(self):
return self.as_text() + '%'
def as_html(self):
output = "
"
def flatten(textobj):
if type(textobj) != types.ListType: textlist = [textobj]
else: textlist = textobj
paragraph = "" ; paralist = []
for t in textlist:
paragraph = paragraph + t.as_html()
if isinstance(t, Break):
paralist.append(paragraph)
paragraph = ""
paralist.append(paragraph)
return paralist
paralist = flatten(self.text)
for para in paralist: output = output + string.strip(para) + '\n'
attr = ""
for i in ['author', 'source']:
if hasattr(self, i):
paralist = flatten(getattr(self, i))
text = string.join(paralist)
attr=attr + ('
' % i) + string.strip(text)
return output + attr
# Text and its subclasses are used to hold chunks of text; instances
# know how to display themselves as plain text or as HTML.
class Text:
"Plain text"
def __init__(self, text=""):
self.text = text
# We need to allow adding a string to Text instances.
def __add__(self, val):
newtext = self.text + str(val)
# __class__ must be used so subclasses create instances of themselves.
return self.__class__(newtext)
def __str__(self): return self.text
def __repr__(self):
s = string.strip(self.text)
if len(s) > 15: s = s[0:15] + '...'
return '<%s: "%s">' % (self.__class__.__name__, s)
def as_text(self): return self.text
def as_html(self): return cgi.escape(self.text)
class PreformattedText(Text):
"Text inside
'
class CodeFormattedText(Text):
"Text inside ..."
def as_text(self):
return str(self.text)
def as_html(self):
return '' + cgi.escape(str(self.text)) + ''
class CitedText(Text):
"Text inside ..."
def as_text(self):
return '_' + simplify(str(self.text)) + '_'
def as_html(self):
return '' + string.strip(cgi.escape(str(self.text))) + ''
class ForeignText(Text):
"Foreign words, from Latin or French or whatever."
def as_text(self):
return '_' + simplify(str(self.text)) + '_'
def as_html(self):
return '' + string.strip(cgi.escape(str(self.text))) + ''
class EmphasizedText(Text):
"Text inside ..."
def as_text(self):
return '*' + simplify(str(self.text)) + '*'
def as_html(self):
return '' + string.strip(cgi.escape(str(self.text))) + ''
class Break(Text):
def as_text(self): return ""
def as_html(self): return "
"
# The QuotationDocHandler class is a SAX handler class that will
# convert a marked-up document using the quotations DTD into a list of
# quotation objects.
class QuotationDocHandler(saxlib.HandlerBase):
def __init__(self, process_func):
self.process_func = process_func
self.newqt = None
# Errors should be signaled, so we'll output a message and raise
# the exception to stop processing
def fatalError(self, exception):
sys.stderr.write('ERROR: '+ str(exception)+'\n')
sys.exit(1)
error = fatalError
warning = fatalError
def characters(self, ch, start, length):
if self.newqt != None:
s = ch[start:start+length]
# Undo the UTF-8 encoding, converting to ISO Latin1, which
# is the default character set used for HTML.
latin1_encode = codecs.lookup('iso-8859-1') [0]
unicode_str = s
s, consumed = latin1_encode( unicode_str )
assert consumed == len( unicode_str )
self.newqt.stack[-1] = self.newqt.stack[-1] + s
def startDocument(self):
self.quote_list = []
def startElement(self, name, attrs):
methname = 'start_'+str(name)
if hasattr(self, methname):
method = getattr(self, methname)
method(attrs)
else:
sys.stderr.write('unknown start tag: <' + name + ' ')
for name, value in attrs.items():
sys.stderr.write(name + '=' + '"' + value + '" ')
sys.stderr.write('>\n')
def endElement(self, name):
methname = 'end_'+str(name)
if hasattr(self, methname):
method = getattr(self, methname)
method()
else:
sys.stderr.write('unknown end tag: ' + name + '>\n')
# There's nothing to be done for the tag
def start_quotations(self, attrs):
pass
def end_quotations(self):
pass
def start_quotation(self, attrs):
if self.newqt == None: self.newqt = Quotation()
def end_quotation(self):
st = self.newqt.stack
for i in range(len(st)):
if type(st[i]) == types.StringType:
st[i] = Text(st[i])
self.newqt.text=self.newqt.text + st
del self.newqt.stack
if self.process_func: self.process_func(self.newqt)
else:
print "Completed quotation\n ", self.newqt.__dict__
self.newqt=Quotation()
# Attributes of a quotation: ... and ...
def start_author(self, data):
# Add the current contents of the stack to the text of the quotation
self.newqt.text = self.newqt.text + self.newqt.stack
# Reset the stack
self.newqt.stack = [ Text() ]
def end_author(self):
# Set the author attribute to contents of the stack; you can't
# have more than one tag per quotation.
self.newqt.author = self.newqt.stack
# Reset the stack for more text.
self.newqt.stack = [ Text() ]
# The code for the tag is exactly parallel to that for
def start_source(self, data):
self.newqt.text = self.newqt.text + self.newqt.stack
self.newqt.stack = [ Text() ]
def end_source(self):
self.newqt.source = self.newqt.stack
self.newqt.stack = [ Text() ]
# Text markups: for breaks,
...
for preformatted
# text, ... for emphasis, ... for citations.
def start_br(self, data):
# Add a Break instance, and a new Text instance.
self.newqt.stack.append(Break())
self.newqt.stack.append( Text() )
def end_br(self): pass
def start_pre(self, data):
self.newqt.stack.append( Text() )
def end_pre(self):
self.newqt.stack[-1] = PreformattedText(self.newqt.stack[-1])
self.newqt.stack.append( Text() )
def start_code(self, data):
self.newqt.stack.append( Text() )
def end_code(self):
self.newqt.stack[-1] = CodeFormattedText(self.newqt.stack[-1])
self.newqt.stack.append( Text() )
def start_em(self, data):
self.newqt.stack.append( Text() )
def end_em(self):
self.newqt.stack[-1] = EmphasizedText(self.newqt.stack[-1])
self.newqt.stack.append( Text() )
def start_cite(self, data):
self.newqt.stack.append( Text() )
def end_cite(self):
self.newqt.stack[-1] = CitedText(self.newqt.stack[-1])
self.newqt.stack.append( Text() )
def start_foreign(self, data):
self.newqt.stack.append( Text() )
def end_foreign(self):
self.newqt.stack[-1] = ForeignText(self.newqt.stack[-1])
self.newqt.stack.append( Text() )
if __name__ == '__main__':
import sys, getopt
# Process the command-line arguments
opts, args = getopt.getopt(sys.argv[1:], 'fthm:r',
['fortune', 'text', 'html', 'max=', 'help',
'randomize'] )
# Set defaults
maxlength = 0 ; method = 'as_fortune'
randomize = 0
# Process arguments
for opt, arg in opts:
if opt in ['-f', '--fortune']:
method='as_fortune'
elif opt in ['-t', '--text']:
method = 'as_text'
elif opt in ['-h', '--html']:
method = 'as_html'
elif opt in ['-m', '--max']:
maxlength = string.atoi(arg)
elif opt in ['-r', '--randomize']:
randomize = 1
elif opt == '--help':
print __doc__ ; sys.exit(0)
# This function will simply output each quotation by calling the
# desired method, as long as it's not suppressed by a setting of
# --max.
qtlist = []
def process_func(qt, qtlist=qtlist, maxlength=maxlength, method=method):
func = getattr(qt, method)
output = func()
length = string.count(output, '\n')
if maxlength!=0 and length > maxlength: return
qtlist.append(output)
# Loop over the input files; use sys.stdin if no files are specified
if len(args) == 0: args = [sys.stdin]
for file in args:
if type(file) == types.StringType: input = open(file, 'r')
else: input = file
# Enforce the use of the Expat parser, because the code needs to be
# sure that the output will be UTF-8 encoded.
p=saxexts.XMLParserFactory.make_parser(["xml.sax.drivers.drv_pyexpat"])
dh = QuotationDocHandler(process_func)
p.setDocumentHandler(dh)
p.setErrorHandler(dh)
p.parseFile(input)
if type(file) == types.StringType: input.close()
p.close()
# Randomize the order of the quotations
if randomize:
import whrandom
q2 = []
for i in range(len(qtlist)):
qt = whrandom.randint(0,len(qtlist)-1 )
q2.append( qtlist[qt] )
qtlist[qt:qt+1] = []
assert len(qtlist) == 0
qtlist = q2
for quote in qtlist:
print quote
# We're done!
PyXML-0.8.2/demo/quotes/quotations.dtd 0100644 0000764 0000144 00000001766 06772561171 017105 0 ustar martin users
PyXML-0.8.2/demo/quotes/sample.xml 0100644 0000764 0000144 00000004512 07175443715 016176 0 ustar martin users
We will perhaps eventually be writing only small modules which are
identified by name as they are used to build larger ones, so that
devices like indentation, rather than delimiters, might become
feasible for expressing local structure in the source language.
Donald E. Knuth, "Structured Programming with goto
Statements", Computing Surveys, Vol 6 No 4, Dec. 1974
I don't know a lot about this artificial life stuff
-- but I'm suspicious of anything Newsweek gets goofy about
-- and I suspect its primary use is as another money extraction tool
to be applied by ai labs to the department of defense
(and more power to 'em).
Nevertheless in wondering why free software is so good these days
it occured to me that the propagation of free software is one gigantic
artificial life evolution experiment, but the metaphor isn't perfect.
Programs are thrown out into the harsh environment, and the bad ones
die. The good ones adapt rapidly and become very robust in short
order.
The only problem with the metaphor is that the process isn't random
at all. Python chooses to include tk's genes; Linux decides
to make itself more suitable for symbiosis with X, etcetera.
Free software is artificial life, but better.
Aaron Watters, 29 Sep 2025
It has also been referred to as the "Don Beaudry hack," but
that's a misnomer. There's nothing hackish about it -- in fact,
it is rather elegant and deep, even though there's something dark
to it.
Guido van Rossum, Metaclass Programming in Python 1.5
This is not a technical issue so much as a human issue; we
are limited and so is our time. (Is this a bug or a feature of time?
Careful; trick question!)
Fred Drake on the Documentation SIG, 9 Sep 2025
Counting is the most simple and primitive of narratives -- 1 2 3 4 5 6
7 8 9 10 -- a tale with a beginning, a middle and an end and a sense
of progression -- arriving at a finish of two digits -- a goal
attained, a denouement reached.
Peter GreenawayFear of Drowning By Numbers (1988)
PyXML-0.8.2/demo/sax/ 0040755 0000764 0000144 00000000000 07614726123 013442 5 ustar martin users PyXML-0.8.2/demo/sax/README 0100644 0000764 0000144 00000002057 07165434556 014332 0 ustar martin users These examples demonstrate the Python SAX API, version 1. In all examples,
the sax driver can be specified by setting the PY_SAX_PARSER environment
variable. Valid settings are
- xml.sax.drivers.drv_pyexpat
- xml.sax.drivers.drw_xmlproc
- xml.sax.drivers.drv_sgmlop
as well as any other driver listed in the xml/sax/drivers directory.
sax2obj.py ???
saxdemo.py Parses an XML file, and prints it in canonical form.
Invoke as 'python saxdemo.py filename.xml'.
The standard driver will be pyexpat.
Alternative drivers can be specified with the -d option
of saxdemo.py; the prefix 'xml.sax.drivers.drv_' is
automatically added to the driver.
saxhack.py appears to be broken
saxstats.py Prints statistics about an xml file.
saxtimer.py Times parsing a document; arguments are the parser name
(the prefix 'xml.sax.drivers.drv_' is automatically added)
and the document name.
saxtrace.py parses a document using xmlproc, and prints all SAX events. PyXML-0.8.2/demo/sax/sax2obj.py 0100644 0000764 0000144 00000010233 07413602740 015353 0 ustar martin users """
A general XML element -> Python object converter based on SAX.
"""
from xml.sax import saxexts,saxlib,saxutils
import re,string
reg_ws=re.compile("[%s]+" % string.whitespace)
class ConvSpec:
"""Contains the information needed to convert SAX events to Python
objects."""
def __init__(self):
pass
class SAXObject:
def __init__(self):
self._fields={}
def has_field(self,field):
return self._fields.has_key(field)
def get_fields(self):
return self._fields.keys()
def get_field(self,field):
return self._fields[field]
def set_field(self,field,value):
self._fields[field]=value
def display(self):
for field in self._fields.keys():
print "%s=%s" % (field,self._fields[field])
def __getattr__(self,attr):
try:
return self._fields[attr]
except KeyError,e:
raise AttributeError(str(e))
def __cmp__(self,obj):
if id(obj)==id(self):
return 0
else:
return 1
class DocHandler(saxlib.DocumentHandler):
def __init__(self,target_elem,list_elems,ign_elems,rep_field):
self.target_elem=target_elem
self.list_elems=list_elems
self.ign_elems=ign_elems
self.rep_field=rep_field
self.ignoring=0
self.objects=[]
self.current=None
self.cur_data=""
self.stack=[]
def startElement(self,name,attrs):
if self.ignoring:
return
if name==self.target_elem:
self.current=SAXObject()
for attr in attrs:
self.current.set_field(attr,attrs[attr])
elif self.list_elems.has_key(name):
if not self.current.has_field(name):
self.current.set_field(name,[])
self.stack.append(self.current)
self.current=SAXObject()
elif self.rep_field.has_key(name) and not self.current.has_field(name):
self.current.set_field(name,[])
else:
if self.ign_elems.has_key(name):
self.ignoring=self.ignoring+1
self.cur_data=""
def characters(self,data,start,length):
if self.ignoring or self.current==None:
return
data=data[start:start+length]
mo=reg_ws.match(data)
if mo!=None and mo.end(0)==len(data):
return
self.cur_data=self.cur_data+data
def endElement(self,name):
if self.ign_elems.has_key(name):
self.ignoring=self.ignoring-1
return
if self.ignoring or self.current==None:
return
if name==self.target_elem:
self.objects.append(self.current)
self.current=None
elif self.list_elems.has_key(name):
obj=self.current
self.current=self.stack[-1]
del self.stack[-1]
self.current.get_field(name).append(obj)
elif self.rep_field.has_key(name):
self.current.get_field(name).append(self.cur_data)
else:
self.current.set_field(name,self.cur_data)
def get_objects(self):
return self.objects
def make_objects(url,element,list_elems={},ign_elems={},rep_field={}):
dh=DocHandler(element,list_elems,ign_elems,rep_field)
eh=saxutils.ErrorPrinter()
parser=saxexts.make_parser()
parser.setDocumentHandler(dh)
parser.setErrorHandler(eh)
parser.parse(url)
return dh.get_objects()
def make_xml(filename,root_elem,trgt_elem,list):
out=open(filename,"w")
out.write("<%s>\n" % root_elem)
for obj in list:
out.write(" <%s>\n" % trgt_elem)
for field in obj.get_fields():
out.write(" <%s>%s%s>\n" % \
(field,escape_markup(obj.get_field(field)),field))
out.write(" %s>\n" % trgt_elem)
out.write("\n%s>" % root_elem)
out.close()
def list2hash(lst,key_field):
hash={}
for obj in lst:
hash[obj.get_field(key_field)]=obj
return hash
def escape_markup(str):
out=""
for ch in str:
if ch=="<":
out=out+"<"
elif ch==">":
out=out+">"
else:
out=out+ch
return out
PyXML-0.8.2/demo/sax/saxdemo.py 0100644 0000764 0000144 00000003145 07534565152 015460 0 ustar martin users # A demo SAX application: using SAX to parse XML documents into ESIS
# or canonical XML.
from xml.sax import saxexts, saxlib, saxutils
import sys,urllib2,getopt
### Interpreting arguments (rather crudely)
try:
(args,trail)=getopt.getopt(sys.argv[1:],"sed:")
assert trail, "No argument provided"
except Exception,e:
print "ERROR: %s" % e
print
print "Usage: python saxdemo.py [-e] [-d drv] filename [outfilename]"
print
print " -e: Output ESIS instead of normalized XML."
print " -s: Silent (no messages except error messages)"
print " -d: Use driver 'drv', where 'drv' is a module name."
print " outfilename: Write to this file."
sys.exit(1)
driver=None
esis=0
silent=0
in_sysID=trail[0]
if len(trail)==2:
out_sysID=trail[1]
else:
out_sysID=""
for (arg,val) in args:
if arg=="-d":
driver="xml.sax.drivers.drv_" + val
elif arg=="-e":
esis=1
elif arg=="-s":
silent=1
p=saxexts.make_parser(driver)
p.setErrorHandler(saxutils.ErrorPrinter())
if out_sysID=="":
out=sys.stdout
else:
try:
out=urllib2.urlopen(out_sysID)
except IOError,e:
print out_sysID+": "+str(e)
if esis:
dh=saxutils.ESISDocHandler(out)
else:
dh=saxutils.Canonizer(out)
### Ready. Let's go!
if not silent:
print "Parser: %s (%s, %s)" % (p.get_parser_name(),p.get_parser_version(),
p.get_driver_version())
print
try:
p.setDocumentHandler(dh)
p.parse(in_sysID)
except IOError,e:
print in_sysID+": "+str(e)
except saxlib.SAXException,e:
print str(e)
### Cleaning up.
out.close()
PyXML-0.8.2/demo/sax/saxhack.py 0100644 0000764 0000144 00000006761 07413602734 015443 0 ustar martin users #
#
# $Id: saxhack.py,v 1.5 2024/12/30 12:17:32 loewis Exp $
#
# illustrate how a saxlib parser can interface directly to sgmlop
#
# history:
# 98-05-23 fl created (derived from the coreXML parser)
#
# Copyright (c) 1998 by Secret Labs AB
#
# info@pythonware.com
# http://www.pythonware.com
#
from xml.sax.saxlib import HandlerBase
class DocumentHandler:#(HandlerBase):
# SAX interface
def startElement(self, tag, attrs):
pass # print "start", tag
def endElement(self, tag):
pass # print "end", tag
def characters(self, text, start, len):
pass # print "data", text[start:start+len]
# --------------------------------------------------------------------
# sgmlop-based parser
from xml.parsers import sgmlop
class Parser:
def setDocumentHandler(self, dh):
self.parser = sgmlop.XMLParser()
self.parser.register(dh, 1)
def parseFile(self, file):
parser = self.parser
while 1:
data = file.read(16384)
if not data:
break
parser.feed(data)
parser.close()
# --------------------------------------------------------------------
# xmllib-based parser
from xml.parsers import xmllib
class xmllibParser(xmllib.XMLParser):
def setDocumentHandler(self, dh):
self.characters = dh.characters
self.unknown_starttag = dh.startElement
self.unknown_endtag = dh.endElement
def handle_data(self, data):
self.characters(data, 0, len(data))
def parseFile(self, file):
while 1:
data = file.read(16384)
if not data:
break
self.feed(data)
self.close()
# --------------------------------------------------------------------
# original xmllib-based parser
class slowParser(xmllib.SlowXMLParser):
def setDocumentHandler(self, dh):
self.characters = dh.characters
self.unknown_starttag = dh.startElement
self.unknown_endtag = dh.endElement
def handle_data(self, data):
self.characters(data, 0, len(data))
def parseFile(self, file):
while 1:
data = file.read(16384)
if not data:
break
self.feed(data)
file.close()
# ====================================================================
# test stuff
import time, os, sys
if len(sys.argv) == 1:
print 'Usage: saxhack.py '
sys.exit(1)
FILE = sys.argv[1]
size = os.stat(FILE)[6]
p = Parser()
dh = DocumentHandler()
p.setDocumentHandler(dh)
f = open(FILE)
t = time.clock()
p.parseFile(f) # dry run
t_direct = time.clock() - t
f.close()
#import sys ; sys.exit(0)
print t_direct
if t_direct == 0:
print 'Measured time was too small; use a larger XML file'
sys.exit(1)
print "sgmlop:", int(size / t_direct), "bytes per second"
p = xmllibParser()
#p=slowParser()
dh = DocumentHandler()
p.setDocumentHandler(dh)
f = open(FILE)
t = time.clock()
p.parseFile(f) # dry run
t_fast = time.clock() - t
f.close()
print "xmllib:", int(size / t_fast), "bytes per second"
p = slowParser()
dh = DocumentHandler()
p.setDocumentHandler(dh)
f = open(FILE)
t = time.clock()
p.parseFile(f) # dry run
t_slow = time.clock() - t
f.close()
print "slow xmllib:", int(size / t_slow), "bytes per second"
print
print "normalized timings:"
print "slow xmllib", 1.0
print "fast xmllib", round(t_fast / t_slow, 2), "(%sx)" % round(t_slow / t_fast, 1)
print "sgmlop ", round(t_direct / t_slow, 2), "(%sx)" % round(t_slow / t_direct, 1)
print
PyXML-0.8.2/demo/sax/saxstats.py 0100644 0000764 0000144 00000002204 07413602740 015654 0 ustar martin users # A simple SAX application that counts the number of elements, attributes and
# processing instructions in a document.
from xml.sax import saxexts
from xml.sax import saxlib
import sys
class CounterHandler(saxlib.DocumentHandler):
def __init__(self):
self.elems=0
self.attrs=0
self.pis=0
def startElement(self,name,attrs):
self.elems=self.elems+1
self.attrs=self.attrs+len(attrs)
def processingInstruction(self,target,data):
self.pis=self.pis+1
# --- Main prog
if len(sys.argv)<2:
print "Usage: python saxstats.py "
print
print " : file name of the document to parse"
sys.exit(1)
# Load parser and driver
print "\nLoading parser..."
p=saxexts.make_parser()
ch=CounterHandler()
p.setDocumentHandler(ch)
# Ready, set, go!
print "Starting parse..."
OK=0
try:
p.parse(sys.argv[1])
OK=1
except IOError,e:
print "\nERROR: "+sys.argv[1]+": "+str(e)
except saxlib.SAXException,e:
print "\nERROR: "+str(e)
print "Parse complete:"
print " Elements: %d" % ch.elems
print " Attributes: %d" % ch.attrs
print " Proc instrs: %d" % ch.pis
PyXML-0.8.2/demo/sax/saxtimer.py 0100644 0000764 0000144 00000002064 07413602740 015642 0 ustar martin users # A simple SAX application that measures the time spent parsing a
# document with an empty document handler.
from xml.sax import saxexts
from xml.sax import saxlib
import sys,time
if len(sys.argv)<3:
print "Usage: python "
print
print " : file name of the document to parse"
print " : driver package name"
sys.exit(1)
# Load parser and driver
print "\nLoading parser..."
try:
p=saxexts.make_parser("xml.sax.drivers.drv_" + sys.argv[1])
except saxlib.SAXException,e:
print "ERROR: Parser not available"
sys.exit(1)
# Ready, set, go!
sum=0
print "Starting parse..."
for ix in range(3):
start=time.clock()
OK=0
pt=0
try:
p.parse(sys.argv[2])
pt=time.clock()-start
OK=1
except IOError,e:
print "\nERROR: "+sys.argv[2]+": "+str(e)
except saxlib.SAXException,e:
print "\nERROR: "+str(e)
if OK:
print "Parse time: "+`pt`
else:
print "Error occurred, parse aborted."
sum=sum+pt
print "Average: %f" % (sum/3.0)
PyXML-0.8.2/demo/sax/saxtrace.py 0100644 0000764 0000144 00000003514 07413602740 015621 0 ustar martin users """
A minimal SAX application that just prints out the document-handler events
it receives.
"""
import sys
from xml.sax import saxexts
# --- SAXtracer
class SAXtracer:
def __init__(self,objname):
self.objname=objname
self.met_name=""
def __getattr__(self,name):
self.met_name=name # UGLY! :)
return self.trace
def error(self,exception):
print "err_handler.error(%s)" % str(exception)
def fatalError(self,exception):
print "err_handler.fatalError(%s)" % str(exception)
def warning(self,exception):
print "err_handler.warning(%s)" % str(exception)
def characters(self,data,start,length):
print "doc_handler.characters(%s,%d,%d)" % (`data[start:start+length]`,
start,length)
def ignorableWhitespace(self,data,start,length):
print "doc_handler.ignorableWhitespace(%s,%d,%d)" % \
(`data[start:start+length]`,start,length)
def startElement(self, name, attrs):
attr_str="{"
for attr in attrs:
attr_str="%s '%s':'%s'," % (attr_str,attr,attrs[attr])
if attr_str=="{":
attr_str="{}"
else:
attr_str=attr_str[:-1]+" }"
print "doc_handler.startElement('%s',%s)" % (name,attr_str)
def trace(self,*rest):
str="%s.%s(" % (self.objname,self.met_name)
for param in rest[:-1]:
str=str+`param`+", "
if len(rest)>0:
print str+`rest[-1]`+")"
else:
print str+")"
# --- Main prog
pf=saxexts.ParserFactory()
p=pf.make_parser("xml.sax.drivers.drv_xmlproc")
p.setDocumentHandler(SAXtracer("doc_handler"))
p.setDTDHandler(SAXtracer("dtd_handler"))
p.setErrorHandler(SAXtracer("err_handler"))
p.setEntityResolver(SAXtracer("ent_handler"))
p.parse(sys.argv[1])
PyXML-0.8.2/demo/sgmlop/ 0040755 0000764 0000144 00000000000 07614726123 014150 5 ustar martin users PyXML-0.8.2/demo/sgmlop/benchsgml.py 0100644 0000764 0000144 00000004006 07413602740 016454 0 ustar martin users # benchmark
import time
from xml.parsers import sgmlop
import sgmllib
SIZE = 16384
FILE = "test2.htm"
bytes = len(open(FILE).read())
def t1():
fp = open(FILE)
parser = sgmllib.SlowSGMLParser()
while 1:
data = fp.read(SIZE)
if not data:
break
parser.feed(data)
parser.close()
fp.close()
def t2():
fp = open(FILE)
parser = sgmllib.FastSGMLParser()
while 1:
data = fp.read(SIZE)
if not data:
break
parser.feed(data)
parser.close()
fp.close()
def t3():
fp = open(FILE)
parser = sgmlop.SGMLParser()
while 1:
data = fp.read(SIZE)
if not data:
break
parser.feed(data)
parser.close()
fp.close()
class Dummy:
def finish_starttag(self, tag, data):
pass
def finish_endtag(self, tag):
pass
def handle_entityref(self, data):
pass
def handle_data(self, data):
pass
def t4():
fp = open(FILE)
parser = sgmlop.SGMLParser()
parser.register(Dummy())
while 1:
data = fp.read(SIZE)
if not data:
break
parser.feed(data)
parser.close()
fp.close()
t = time.time()
t1(); t1(); t1(); t1(); t1();
t1(); t1(); t1(); t1(); t1();
t = (time.time() - t) / 10
print "t1:", t
if t: print int(bytes / t), "bytes per second"
t = time.time()
t2(); t2(); t2(); t2(); t2();
t2(); t2(); t2(); t2(); t2();
t2(); t2(); t2(); t2(); t2();
t2(); t2(); t2(); t2(); t2();
t = (time.time() - t) / 20
print "t2:", t
if t: print int(bytes / t), "bytes per second"
t = time.time()
t3(); t3(); t3(); t3(); t3();
t3(); t3(); t3(); t3(); t3();
t3(); t3(); t3(); t3(); t3();
t3(); t3(); t3(); t3(); t3();
t = (time.time() - t) / 20
print "t3:", t
if t: print int(bytes / t), "bytes per second"
t = time.time()
t4(); t4(); t4(); t4(); t4();
t4(); t4(); t4(); t4(); t4();
t4(); t4(); t4(); t4(); t4();
t4(); t4(); t4(); t4(); t4();
t = (time.time() - t) / 20
print "t4:", t
if t: print int(bytes / t), "bytes per second"
PyXML-0.8.2/demo/sgmlop/benchxml.py 0100644 0000764 0000144 00000010603 07413602740 016312 0 ustar martin users # benchmark
import time, sys, os
from xml.parsers import xmllib, sgmlop
SIZE = 16384
FILE = "hamlet.xml"
try:
FILE = sys.argv[1]
except IndexError:
pass
print "---", FILE, "---"
bytes = os.stat(FILE)[6]
# --------------------------------------------------------------------
# 1) sgmlop with null parser (no registered callbacks)
def test1():
fp = open(FILE)
parser = sgmlop.XMLParser()
while 1:
data = fp.read(SIZE)
if not data:
break
parser.feed(data)
parser.close()
fp.close()
# --------------------------------------------------------------------
# 2) sgmlop with dummy parser
class sgmlopDummy:
def finish_starttag(self, tag, data):
pass
def finish_endtag(self, tag):
pass
def handle_entityref(self, data):
pass
def handle_data(self, data):
pass
def handle_proc(self, name, data):
pass
def handle_cdata(self, data):
pass
def handle_charref(self, data):
pass
def handle_comment(self, data):
pass
def handle_special(self, data):
pass
def test2():
fp = open(FILE)
out = sgmlopDummy()
parser = sgmlop.XMLParser()
parser.register(out)
while 1:
data = fp.read(SIZE)
if not data:
break
parser.feed(data)
parser.close()
fp.close()
# --------------------------------------------------------------------
# 3) accelerated xmllib
class FastXMLParser(xmllib.FastXMLParser):
def unknown_starttag(self, tag, data):
pass
def unknown_endtag(self, tag):
pass
def handle_entityref(self, data):
pass
def handle_data(self, data):
pass
def handle_cdata(self, data):
pass
def test3():
fp = open(FILE)
parser = FastXMLParser()
while 1:
data = fp.read(SIZE)
if not data:
break
parser.feed(data)
parser.close()
fp.close()
# --------------------------------------------------------------------
# 4) old xmllib
class SlowXMLParser(xmllib.SlowXMLParser):
def unknown_starttag(self, tag, data):
pass
def unknown_endtag(self, tag):
pass
def handle_entityref(self, data):
pass
def handle_data(self, data):
pass
def handle_cdata(self, data):
pass
def test4():
fp = open(FILE)
parser = SlowXMLParser()
while 1:
data = fp.read(SIZE)
if not data:
break
parser.feed(data)
parser.close()
fp.close()
# --------------------------------------------------------------------
# 5) xmltok parser
try:
import xmltok
except (ImportError, SystemError):
xmltok = None
class xmltokDummy:
def do_tag(self, tag, data):
pass
def do_endtag(self, tag):
pass
def do_entity(self, tag, data):
pass
def do_data(self, data):
pass
def test5():
fp = open(FILE)
out = xmltokDummy()
parser = xmltok.ParserCreate()
parser.StartElementHandler = out.do_tag
parser.EndElementHandler = out.do_endtag
parser.CharacterDataHandler = out.do_data
parser.ProcessingInstructionHandler = out.do_entity
while 1:
data = fp.read(SIZE)
if not data:
break
parser.Parse(data)
parser.Parse("", 1)
fp.close()
# ====================================================================
# main
test = test1
t = time.clock()
test(); test(); test(); test(); test();
t = (time.clock() - t) / 5
print "sgmlop/null parser:", round(t, 3), "seconds;",
print int(bytes / t), "bytes per second"
time1 = t
test = test2
t = time.clock()
test(); test(); test(); test(); test();
t = (time.clock() - t) / 5
print "sgmlop/dummy parser:", round(t, 3), "seconds;",
print int(bytes / t), "bytes per second"
time2 = t
test = test3
t = time.clock()
test(); test();
t = (time.clock() - t) / 2
print "xmllib/fast parser:", round(t, 3), "seconds;",
print int(bytes / t), "bytes per second"
time3 = t
test = test4
t = time.clock()
test();
t = (time.clock() - t) / 1
print "xmllib/slow parser:", round(t, 3), "seconds;",
print int(bytes / t), "bytes per second"
time4 = t
print
print "normalized timings:"
print "slow xmllib ", 1.0
print "fast xmllib ", round(time3/time4, 3), "(%sx)" % round(time4/time3, 1)
print "sgmlop dummy", round(time2/time4, 3), "(%sx)" % round(time4/time2, 1)
print "sgmlop null ", round(time1/time4, 3), "(%sx)" % round(time4/time1, 1)
print
PyXML-0.8.2/demo/sgmlop/test2.htm 0100644 0000764 0000144 00000000000 06631372347 015711 0 ustar martin users PyXML-0.8.2/demo/sgmlop/testxml1.py 0100644 0000764 0000144 00000013407 07413574667 016320 0 ustar martin users # basic tests
import sys
import time, string
from xml.parsers import sgmlop
try:
from xml.parsers import xmllib
have_xmllib = 1
except ImportError:
have_xmllib = 0
class xmllib:
class FastXMLParser:pass
class SlowXMLParser:pass
try:
FILE, VERBOSE = sys.argv[1], 2
except IndexError:
FILE, VERBOSE = "hamlet.xml", 1
print
print "test collecting parsers on", FILE
print
# --------------------------------------------------------------------
# sgmlop
class myCollector:
def __init__(self):
self.data = []
self.text = []
def finish_starttag(self, tag, data):
if self.text:
self.data.append(repr(string.join(self.text, "")))
self.text = []
self.data.append(("start", tag, data))
def handle_proc(self, tag, data):
if self.text:
self.data.append(repr(string.join(self.text, "")))
self.text = []
self.data.append(("pi", tag, data))
def handle_special(self, data):
if self.text:
self.data.append(repr(string.join(self.text, "")))
self.text = []
self.data.append(("special", data))
def handle_entityref(self, data):
if self.text:
self.data.append(repr(string.join(self.text, "")))
self.text = []
self.data.append(("entity", data))
def handle_data(self, data):
self.text.append(data)
def handle_cdata(self, data):
self.text.append("CDATA" + data)
t = time.clock()
for i in range(1000):
out = myCollector()
fp = open(FILE)
parser = sgmlop.XMLUnicodeParser()
parser.register(out)
b = 0
while 1:
data = fp.read(1024)
if not data:
break
parser.feed(data)
b = b + len(data)
parser.close()
t1 = time.clock() - t
print "raw sgmlop:", len(out.data), "items;", round(t1, 3), "seconds;",
print round(b / t1 / 1024, 2), "kbytes per second"
print out.data
# --------------------------------------------------------------------
# xmllib
class FastXMLParser(xmllib.FastXMLParser):
def __init__(self):
xmllib.FastXMLParser.__init__(self)
self.data = []
self.text = []
def unknown_starttag(self, tag, data):
if self.text:
self.data.append(repr(string.join(self.text, "")))
self.text = []
self.data.append("start", tag, data)
def handle_proc(self, tag, data):
if self.text:
self.data.append(repr(string.join(self.text, "")))
self.text = []
self.data.append("pi", tag, data)
def handle_special(self, data):
if self.text:
self.data.append(repr(string.join(self.text, "")))
self.text = []
self.data.append("special", data)
def handle_entityref(self, data):
if self.text:
self.data.append(repr(string.join(self.text, "")))
self.text = []
self.data.append("entity", data)
def handle_data(self, data):
self.text.append(data)
def handle_cdata(self, data):
self.text.append("CDATA" + data)
if have_xmllib:
t = time.clock()
for i in range(1):
fp = open(FILE)
parser2 = FastXMLParser()
b = 0
while 1:
data = fp.read(1024)
if not data:
break
parser2.feed(data)
b = b + len(data)
parser2.close()
t2 = time.clock() - t
print "fast xmllib:", len(parser2.data), "items;", round(t2, 3), "seconds;",
print round(b / t2 / 1024, 2), "kbytes per second"
class SlowXMLParser(xmllib.SlowXMLParser):
def __init__(self):
xmllib.SlowXMLParser.__init__(self)
self.data = []
self.text = []
def unknown_starttag(self, tag, data):
if self.text:
self.data.append(repr(string.join(self.text, "")))
self.text = []
self.data.append("start", tag, data)
def handle_proc(self, tag, data):
if self.text:
self.data.append(repr(string.join(self.text, "")))
self.text = []
self.data.append("pi", tag, data)
def handle_special(self, data):
if self.text:
self.data.append(repr(string.join(self.text, "")))
self.text = []
self.data.append("special", data)
def handle_entityref(self, data):
if self.text:
self.data.append(repr(string.join(self.text, "")))
self.text = []
self.data.append("entity", data)
def handle_data(self, data):
self.text.append(data)
def handle_cdata(self, data):
self.text.append("CDATA" + data)
if have_xmllib:
t = time.clock()
for i in range(1):
fp = open(FILE)
parser3 = SlowXMLParser()
b = 0
while 1:
data = fp.read(1024)
if not data:
break
parser3.feed(data)
b = b + len(data)
parser3.close()
t3 = time.clock() - t
print "slow xmllib:", len(parser3.data), "items;", round(t3, 3), "seconds;",
print round(b / t3 / 1024, 2), "kbytes per second"
print
print "normalized timing:"
print "slow xmllib", 1.0
print "fast xmllib", round(t2 / t3, 2), "(%sx)" % round(t3 / t2, 1)
print "sgmlop ", round(t1 / t3, 2), "(%sx)" % round(t3 / t1, 1)
print
print "looking for differences:"
items = min(len(parser2.data), len(parser3.data))
for i in xrange(items):
if parser2.data[i] != parser3.data[i]:
for j in range(max(i-5, 0), min(i+5, items)):
if parser2.data[j] != parser3.data[j]:
print "+", j+1, parser2.data[j]
print "*", j+1, parser3.data[j]
else:
print "=", j+1, parser2.data[j]
break
else:
print " (none found)"
PyXML-0.8.2/demo/sgmlop/testxml2.py 0100644 0000764 0000144 00000002625 06635616746 016321 0 ustar martin users # dry runs
from xml.parsers import xmllib, sgmlop
import sys
import time, string
try:
FILE, VERBOSE = sys.argv[1], 2
except IndexError:
FILE, VERBOSE = "hamlet.xml", 1
BLOCK = 16384
print
print "test empty parsers on", FILE
print
t = time.clock()
b = 0
for i in range(1):
fp = open(FILE)
parser = sgmlop.XMLParser()
while 1:
data = fp.read(BLOCK)
if not data:
break
parser.feed(data)
b = b + len(data)
parser.close()
t1 = time.clock() - t
print "sgmlop", round(t1, 3), "seconds;",
print round(b / t1 / 1024, 2), "kbytes per second"
t = time.clock()
b = 0
for i in range(1):
fp = open(FILE)
parser = xmllib.FastXMLParser()
while 1:
data = fp.read(BLOCK)
if not data:
break
parser.feed(data)
b = b + len(data)
parser.close()
t2 = time.clock() - t
print "fast xmllib", round(t2, 3), "seconds;",
print round(b / t2 / 1024, 2), "kbytes per second"
t = time.clock()
b = 0
for i in range(1):
fp = open(FILE)
parser = xmllib.SlowXMLParser()
while 1:
data = fp.read(BLOCK)
if not data:
break
parser.feed(data)
b = b + len(data)
parser.close()
t3 = time.clock() - t
print "slow xmllib", round(t3, 3), "seconds;",
print round(b / t3 / 1024, 2), "kbytes per second"
print
print "sgmlop is", round(t3 / t1, 2), "times faster than slow xmllib"
PyXML-0.8.2/demo/xbel/ 0040755 0000764 0000144 00000000000 07614726123 013601 5 ustar martin users PyXML-0.8.2/demo/xbel/doc/ 0040755 0000764 0000144 00000000000 07614726123 014346 5 ustar martin users PyXML-0.8.2/demo/xbel/doc/xbel.bib 0100644 0000764 0000144 00000007003 06620203620 015737 0 ustar martin users % This is the bibliography database for the XBEL report.
@book(unicode20,
title = "The {U}nicode Standard, Version 2.0",
author = "The {U}nicode Consotium",
publisher = "Addison-Wesley Developers Press",
address = "Reading, MA",
year = "1996",
isbn = "0-201-48345-9"
)
@techreport(unicode21,
title = "The {U}nicode Standard, Version 2.1",
author = "The {U}nicode Consortium",
institution = "The {U}nicode Consortium",
year = "1998",
month = "Sep",
number = "8",
address = "San Jose, CA",
note = "\url{http://www.unicode.org/unicode/reports/tr8.html}"
)
@book(iso8601,
title = "Data elements and interchange formats --- Information
interchange --- Representation of dates and times",
author = "International Organization for Standardization",
publisher = "International Organization for Standardization",
year = "1988"
)
@techreport(w3c-xml,
author = "Tim Bray and Jean Paoli and C. M. Sperberg-McQueen",
title = "Extensible Markup Language ({XML}) 1.0",
institution = "World Wide Web Consortium",
type = "Recommendation",
year = "1998",
month = "Feb",
note = "\url{http://www.w3.org/TR/REC-xml}"
)
@techreport(w3c-xml-names,
author = "Tim Bray and Dave Hollander and Andrew Layman",
title = "Namespaces in {XML}",
institution = "World Wide Web Consortium",
type = "Working Draft",
year = "1998",
month = "Sep",
note = "\url{http://www.w3.org/TR/WD-xml-names}"
)
@techreport(w3c-rdf-syntax,
author = "Ora Lassila and Ralph R. Swick",
title = "Resource Description Framework
({RDF}) Model and Syntax Specification",
institution = "World Wide Web Consortium",
type = "Working Draft",
year = "1998",
month = "Oct",
note = "\url{http://www.w3.org/TR/WD-rdf-syntax}"
)
@techreport(w3c-rdf-schema,
author = "Dan Brickley and R. V. Guha and Andrew Layman",
title = "Resource Description Framework
({RDF}) Schema Specification",
institution = "World Wide Web Consortium",
type = "Working Draft",
year = "1998",
month = "Aug",
note = "\url{http://www.w3.org/TR/WD-rdf-schema}"
)
@techreport(w3c-datetime,
author = "Misha Wolf and Charles Wicksteed",
title = "Date and Time Formats",
institution = "World Wide Web Consortium",
type = "Technical note",
year = "1998",
month = "Sep",
note = "\url{http://www.w3.org/TR/WD-rdf-schema}"
)
@manual(w3c-xmlspec,
author = "Eve Maler",
title = "W3C XML Specification DTD (`XMLspec')",
organization = "World Wide Web Consortium",
month = "Sep",
year = "1998",
note = "\url{http://www.w3.org/XML/1998/06/xmlspec-report-19980910.htm}"
)
@misc(iso8601-houston,
author = "Gary Houston",
title = "{ISO} 8601 Date/Time Representations",
year = "1993",
month = "Jan",
note = "\url{ftp://ftp.informatik.uni-erlangen.de/pub/doc/ISO/ISO8601.ps.Z}"
)
@misc(iso8601-kuhn,
author = "Markus Kuhn",
title = "A Summary of the International Standard Date
and Time Notation",
year = "1998",
month = "Sep",
note = "\url{http://www.cl.cam.ac.uk/~mgk25/iso-time.html}"
)
% The "author" field here is completely bogus:
@misc(dublin-core,
title = "Dublin Core Metadata",
author = "{Dublin Core Working Group}",
year = "1997",
month = "Nov",
note = "\url{http://purl.oclc.org/metadata/dublin_core/}"
)
@misc(python-xml,
title = "Python and {XML} Processing",
author = "Andrew M. Kuchling",
note = "\url{http://www.python.org/topics/xml/}"
)
@misc(xbel-home,
title = "The {XML} Bookmark Exchange Language Resource Page",
author = "Drake, Jr., Fred L.",
note = "\url{http://www.python.org/topics/xml/xbel/}"
)
PyXML-0.8.2/demo/xbel/doc/xbel.tex 0100644 0000764 0000144 00000077514 07263756426 016046 0 ustar martin users % When generating HTML, use:
% mkhowto --html --iconserver . --split 4 --link 2 xbel
%
% The catch:
% You have to be running the version of mkhowto from the Python
% 1.5.2 (post-alpha2) tree, since that's when I added bibtex
% support. ;-)
\documentclass{howto}
\usepackage{verbatim}
% define some local macros:
\newcommand{\element}[1]{\texttt{<#1>}}
\newcommand{\attribute}[1]{\texttt{#1}}
\newcommand{\nmtoken}[1]{\texttt{#1}}
\newcommand{\paramentity}[1]{\texttt{\char`\%#1;}}
\newenvironment{longexample}
{\begingroup\small}
{\endgroup}
\newcommand{\contributor}[2]{\term{#1 \textnormal{(\email{#2})}}}
\newenvironment{contributorlist}
{\begin{definitions}}
{\end{definitions}}
\title{The XML Bookmark Exchange Language}
\author{Fred L. Drake, Jr.}
\authoraddress{
PythonLabs at Digital Creations \\
E-mail: \email{fdrake@acm.org}
}
\date{\today} % XXX update before release!
\release{1.1}
\setshortversion{1.1}
\begin{document}
\maketitle
\begin{abstract}
\noindent
The XML Bookmark Exchange Language (XBEL) is a rich interchange
format for ``bookmark'' data as used by most Internet browsers. This
document describes the origin of the design, the requirements which
drove the design process, and the resulting document type.
\end{abstract}
\tableofcontents
\section{Introduction
\label{intro}}
The XML Bookmark Exchange Language, or XBEL, is an interchange
format for the hierarchical bookmark data used by current Internet
browsers. It is defined as an application of the Extensible Markup
Language, or XML \cite{w3c-xml}.
This section descibes the origin of the effort which created the XML
Bookmark Exchange Language (XBEL), identifies the contributors, and
provides information on the availability of the public text of the
DTD and additional documentation on the applications which support
XBEL.
\subsection{Origins
\label{origins}}
The XML Bookmark Exchange Language is a product of the Python XML
Special Interest Group (XML-SIG). The initial intent of the XBEL
effort was to create a demonstration of XML facilities available
to Python programmers which would also be useful.
\subsection{Contributors
\label{contrib}}
The initial idea for XBEL was contributed by Mark Hammond. Mark
sent his idea to the Python XML-SIG mailing list. This was closely
followed by discussions and additional ideas by many of the list
participants. The following people contributed to the design of
the DTD and the related software (listed in alphabetical order by
last name):
\begin{contributorlist}
\contributor{Fred L. Drake, Jr.}{fdrake@acm.org}
Documentation. Design input on DTD and the storage of
metadata. Implemented direct support for XBEL in Grail.
\contributor{David Faure}{david@mandrakesoft.com}
Suggested adding the \attribute{icon} attribute to
\element{folder} and \element{bookmark} elements, and
\attribute{icon} to \element{folder}. Implemented XBEL in the
Konqueror file manager for the K Desktop Envionment (KDE).
\contributor{Stefane Fermigier}{fermigie@math.jussieu.fr}
Modified implementation of software for Internet Explorer
Favorites conversion using his original Python DOM
implementation.
\contributor{Lars Marius Garshol}{larsga@garshol.priv.no}
Extended the concept to cover all Internet browsers bookmarks
and came up with the name and acronym. Implemented support
for Navigator and Opera bookmark formats.
\contributor{Geir Ove Gr{\o}nmo}{grove@infotek.no}
General input on XML and the desired level of complexity.
\contributor{Marc van Grootel}{bwaumg@urc.tue.nl}
Design input on the DTD, storage of metadata, and comments on
the use of XBEL with architectural forms.
\contributor{Mark Hammond}{MHammond@skippinet.com.au}
Original concept and DTD for an archival storage format for
Internet Explorer ``Favorites.''
\contributor{Jack Jansen}{Jack.Jansen@cwi.nl}
General input on potential advanced applications.
\contributor{Andrew M. Kuchling}{akuchling@acm.org}
Implemented conversion software between XBEL and Lynx
bookmarks.
\contributor{Fredrik Lundh}{fredrik@pythonware.com}
Initial software implementation for Internet Explorer.
\contributor{Sean McGrath}{digitome@iol.ie}
General input on XML and document type definitions.
\contributor{Greg Stein}{gstein@lyra.org}
General input on XML Namespaces and moderator of complexity.
\contributor{Walter R. Underwood}{wunder@infoseek.com}
General input on the use of XML character entites instead of
adding general entities, and discussion on date/time values in
XML.
\end{contributorlist}
\subsection{Availability
\label{availability}}
Information on XBEL, including the public text and this document,
is available on the Python XML-SIG Web site at
\url{http://pyxml.sourceforge.net/topics/xml/xbel/} \cite{xbel-home}.
Please refer to this Web resource for information on new versions,
DTD variants, and supporting software.
The public text for XBEL will be made available through a SOCAT
catalog at available at:
\url{http://pyxml.sourceforge.net/topics/xml/dtds/catalog}. This
catalog may be used by including a DELEGATE entry in a catalog
already used by XML processing software. The DELEGATE entry
should be:
\begin{verbatim}
DELEGATE "+//IDN python.org" "http://www.python.org/topics/xml/dtds/catalog"
\end{verbatim}
\subsection{Formal Identification
\label{formal-ident}}
The XBEL DTD documented in this report has the Formal Public
Identifier:
\begin{verbatim}
+//IDN python.org//DTD XML Bookmark Exchange Language 1.1//EN//XML
\end{verbatim}
Valid instances of this document type may use the following document
type declaration:
\begin{verbatim}
\end{verbatim}
\section{Requirements
\label{requirements}}
This section describes the functional capabilities which this
document type supports. There are three categories of
functionality supported: basic bookmark exchange between browsers,
data storage for advanced Internet resource management tools, and
simplicity in extending the DTD if needed for specific
applications.
\subsection{Relation to Browser Functionality
\label{req-browser}}
XBEL instances must be able to describe sufficient data to
represent the bookmarks of all major Internet browsers.
It must be possible to convert browser-specific bookmark data to
XBEL in a lossless manner, though specific conversions may remove
data for application-specific reasons. It is especially important
to consider privacy issues when exchanging bookmark data.
Conversion from XBEL to a browser-specific format may lose
information when the data originates from a browser supporting
bookmark features not available in all browsers. It is expected
that software implementing the conversion be able to warn the user
if conversion will cause the loss of information, as appropriate.
\subsection{Advanced Application Support
\label{req-applications}}
XBEL must be able to support interchange requirements for
applications not currently implemented as part of typical Internet
browsers, including (but not limited to!) application-specific
preference and history information which only pertains to specific
bookmarks, metadata information, and alternate sources or formats
for the documents.
It must be possible for applications to operate on subsets of the
information stored in an XBEL instance without affecting private
information stored by other applications. Application-specific
data stored in an XBEL instance may be simple text or may be
heavily structured.
\subsection{Extensibility
\label{req-extensibility}}
Some ability to extend the document type definition is required to
encourage reuse of the existing design. Due to the use of XML,
only a minimum of inherant flexibility is required, as new
document types may be formed using namespaces or by allowing the
use of well-formed but possibly invalid markup \cite{w3c-xml-names}.
\section{XBEL Document Structure
\label{document-structure}}
This section describes the structure of XBEL documents. This
includes information on each element and attribute defined in the
DTD. Some descriptions include references to the parameter entities
used to construct the DTD; these are described in Section
\ref{parameter-entities}, ``Use of Parameter Entities.''
\subsection{Date/time Attribute Values
\label{date-time}}
Several attributes defined in this document type require date/time
values stored as CDATA. For these attributes, the value must be
formatted as an ISO 8601:1988 value containing a date
\cite{iso8601,iso8601-houston,iso8601-kuhn}. A time value
should be supplied whenever the information is available to the
application which set the value. The format of the values is
restricted to the forms specified in the profile defined in
\emph{Date and Time Formats} \cite{w3c-datetime}. Attributes
which require this form of value are described below as having a
\dfn{date/time value} rather than a CDATA value.
\subsection{Top-level Information
\label{top-level}}
This section describes the top-level element type of XBEL
documents.
\subsubsection{The \element{xbel} Element
\label{element-xbel}}
The \element{xbel} element defines the top-level data structure
stored in an XBEL instance. It may contain optional
\element{title}, \element{info}, and \element{desc} elements,
followed by any number of elements from
\paramentity{nodes.mix}. This is similar to the
\element{folder} element, but it may not be nested and carries
different attributes.
\paragraph*{Attributes}
The \element{xbel} element carries a \attribute{version}
attribute which has a fixed value that specifies the version
of the XBEL DTD. Other attributes indicate the similarity to
the \element{folder} element.
\begin{definitions}
\term{\attribute{version}, \emph{fixed}}
Fixed value which specifies the version of the DTD in use.
\term{\attribute{id}}
ID value to allow linking to this element; only the
\element{alias} element's \attribute{ref} attribute supports
a corresponding IDREF value.
\term{\attribute{added}}
Date/time value which can be used to record when the
collection of bookmarks was created.
\end{definitions}
\paragraph*{Processing Expectations}
The \element{xbel} element is in many ways similar to a
\element{folder} element, but may not be ``folded.''
Auxillary information, such as an optional \element{title}
element, may be shown in a substantially different way than
for \element{folder} in a user interface.
\subsection{Common Elements
\label{common-elements}}
Elements described in this section may occur in different contexts
within an XBEL instance, but share fundamental semantic
interpretation in each case.
\subsubsection{The \element{title} Element
\label{element-title}}
The \element{title} element is used to mark the title associated
with the immediately enclosing element. It is used for
the \element{xbel}, \element{folder}, and \element{bookmark}
elements. This element is always optional and may contain
only character data.
\paragraph*{Processing Expectations}
Software which presents bookmark information to the user in
any form should use the content of this element to identify
the resource to the user. Additional information may be
needed to make the identification unambiguous.
Applications may use the text of the \element{title}
during search operations.
\paragraph*{Rationale}
Many Internet resources are described by a short title, often
displayed by the bookmarking facilities. Storing the title
allows a significant improvement in user interface
responsiveness when compared to retrieving the resource to
reload the title. Title storage is the approach taken by all
browsers known to the XBEL designers.
\subsubsection{The \element{desc} Element
\label{element-desc}}
The \element{desc} element is used to store a human-readable
description of the enclosing element. For a \element{folder} or
the \element{xbel} element,
this may be used to more thoroughly explain the subject of the
bookmarks stored in the collection and why they may be
interesting. For a \element{bookmark}, a summary of the
resource pointed to by the bookmark may be more appropriate.
This element is always optional and may contain only character
data.
\paragraph*{Processing Expectations}
The content of this element may be displayed to a user
requesting more information on the folder or bookmark
containing the description. In the case of a
\element{bookmark}, this can be used before actually making a
request over the network to retrieve the resource.
Applications may use the text of the \element{desc}
during search operations.
\paragraph*{Rationale}
Many Internet browsers support simple annotation of bookmark
data with human readable text. This element is required to
support exchange of this data.
\subsubsection{The \element{info} Element
\label{element-info}}
The \element{info} element is used to store metadata related to
the immediately enclosing element. The intended use is for
\element{info} to store a series of \element{metadata} elements,
each of which ``belongs'' to some application. An
``application'' in this sense may be either a program, such as a
specific Internet browser, or a more general metadata scheme,
such as the Dublin Core \cite{dublin-core}.
The \element{info} element is always optional. If present, it
must contain one or more \element{metadata} elements.
\paragraph*{Processing Expectations}
Applications are expected to ignore \element{info} elements if
they are not able to deal with the contents of constituent
\element{metadata} elements. Whether or not \element{info}
elements should be ``passed through'' transparently or removed
depends on the purpose of the processing application, but an
effort should be made to retain the information whenever the
enclosing element is retained, even in a modified form.
\paragraph*{Rationale}
This element provides a clean way of isolating
application-specific metadata from more generally supported
constructs within the bookmark data.
\subsubsection{The \element{metadata} Element
\label{element-metadata}}
The \element{metadata} element is used as a container for all
auxillary information related to a node which belongs to a
single metadata scheme. The specific contents of
\element{metadata} is highly dependent on the metadata scheme
which applies; XML namespaces should be used to identify
explicit markup used within the element.
The DTD for XBEL specifies the content model for
\element{metadata} as \code{EMPTY}, but any content should be
considered acceptable so long as the XBEL document is
well-formed. The use of \code{EMPTY} avoids making the DTD too
loose; applications which do not validate need not be
concerned. Derivative DTDs can define the parameter entity
\paramentity{metadata.mix} to be the appropriate content model
for the application.
\element{metadata} elements are always optional. Note that an
\element{info} element which contains no \element{metadata}
elements must be removed.
\paragraph*{Attributes}
\begin{definitions}
\term{\attribute{owner}, \emph{required}}
CDATA value specifies the application which ``owns'' the
content of the element. The value of this attribute
should be a URI which refers to a definition of the
application and content structure in either human- or
machine-processible form. It is not required that the URI
be addressable through the network.
\end{definitions}
It is expected that namespace attributes will be added to
the element to specify the markup defined for the content of
the \element{metadata} element.
\paragraph*{Processing Expectations}
Within an \element{info} element, each \element{metadata}
element is required to have a unique value for the
\attribute{owner} attribute. Programs which modify the
contents of \element{metadata} elements should ensure that
only one \element{metadata} exists for any \attribute{owner}
value normally modified by the application within affected
\element{info} elements. \element{metadata} elements for
other owners should remain unaffected.
Specific interpretation of \element{metadata} content is
highly dependent on both the \attribute{owner} and the
application, and is not otherwise within the scope of this
document.
\paragraph*{Rationale}
The \element{metadata} element is required to support owner
identification. It is entirely reasonable for multiple owners
of data to share a document type for their information, but
otherwise require separate processing. The Resource
Description Framework provides an example of an approach which
would require multiple applications to share a namespace
\cite{w3c-rdf-syntax,w3c-rdf-schema}. Some additional form of
ownership identification is required to ensure processors can
avoid destroying each other's data.
\subsection{Data Organization
\label{data-organization}}
The elements described in this section are used to impose
organization on a collection of \element{bookmark} nodes.
\element{folder} is used to support hierarchical organization and
\element{separator} is used to support non-hierarchical
organization.
\subsubsection{The \element{folder} Element
\label{element-folder}}
The \element{folder} element is the element used to support
hierarchical data organization. It is the only element type
which is allowed to nest within itself.
This element may contain optional \element{title},
\element{info} and \element{desc} elements. After this, any
number of elements from \paramentity{nodes.mix} are allowed.
\paragraph*{Attributes}
\begin{definitions}
\term{\attribute{id}}
ID value to allow linking to this element; only the
\element{alias} element's \attribute{ref} attribute supports
a corresponding IDREF value.
\term{\attribute{added}}
Date/time value which records when the folder was added to
the bookmark collection represented by the instance.
\term{\attribute{folded}}
Token which records whether the contents of the folder
should be displayed by default in a user interface. The
value may be \nmtoken{yes} or \nmtoken{no}.
\term{\attribute{icon}}
The value of this attribute is a name which identifies an
icon that the user agent can use to mark the folder for the
user. The value must be mapped to an actual icon; is it not
a URI which points to an image file, since the names should
(in theory) be usable in multiple user agents which have
differing capabilities for image display, and may require
different format or sizes of icon. Mechanisms to do this
are outside the scope of this specification.
\term{\attribute{toolbar}}
Token which records whether the contents of the folder
should be used for the ``Personal Toolbar'' provided by some
user agents. The value may be \nmtoken{yes} or \nmtoken{no}.
\end{definitions}
\paragraph*{Processing Expectations}
User interfaces should display \element{folder} elements as
collapsing lists, allowing the user to display or hide the
contents of the element on demand. Appropriate behavior
outside of user interfaces is expected to be application
specific.
\paragraph*{Rationale}
The \element{folder} element may be used to represent
hierarchical relationships within a collection of bookmarks,
as deployed in current Internet browsers.
The \attribute{toolbar} attribute is needed to support the
``Personal Toolbar'' information from Netscape Navigator.
\subsubsection{The \element{separator} Element
\label{element-separator}}
The \element{separator} element can be used to separate
bookmarks within a collection in a non-hierarchical fashion. It
may be used within a \element{folder} or the \element{xbel}
element.
\paragraph*{Processing Expectations}
The presence of this element may be represented by displaying
a horizontal line or vertical whitespace in an interactive
user interface or printed representation.
\paragraph*{Rationale}
A simple separator is required to support the bookmark
structures of existing Internet browsers.
\subsection{Bookmark Data
\label{bookmark-data}}
Only one element type is used to encapsulate information specific
to an individual bookmark. No need for alternate elements has
been demonstrated.
\subsubsection{The \element{bookmark} Element
\label{element-bookmark}}
A \element{bookmark} element is used to store information about
a specific resource. This element may contain the optional
elements \element{title}, \element{info} and \element{desc}.
\paragraph*{Attributes}
The \element{bookmark} element carries more attributes than
other elements defined in XBEL. These attributes are used to
carry much of the common information maintained on bookmarks
by the major browsers.
\begin{definitions}
\term{\attribute{href}, \emph{required}}
URI which specifies the resource described by the
\element{bookmark} element.
\term{\attribute{id}}
ID value to allow linking to this element; only the
\element{alias} element's \attribute{ref} attribute supports
a corresponding IDREF value.
\term{\attribute{icon}}
This is identical to the \attribute{icon} attribute of the
\element{folder} element; refer to that description for
information.
\term{\attribute{added}}
Date/time value which indicates when the \element{bookmark}
element was added to the bookmark collection.
\term{\attribute{modified}}
Date/time value which records the time of the
last known change to the resource identified by the
\element{bookmark}.
\term{\attribute{visited}}
Date/time value which represents the time of the user's last
``visit'' to the resource. Note that the value for
\attribute{modified} may be more recent than the value for
\attribute{visited} if software is used that checks for
resources which have changed since the user last visited the
resource. This feature is increasingly common in browsers.
\end{definitions}
\paragraph*{Processing Expectations}
In a user interface, \element{bookmark} should typically be
represented by the contents of the \element{title} element, if
present. The representation of the bookmark should be
``hot,'' allowing traversal to the referenced resource by the
user. Additional information on the resource, such as the
description given in a \element{desc} element, should be
available to the user on demand.
Outside a user interface, processing may be too
application-specific to discuss here.
\paragraph*{Rationale}
The use of a single structured element type to represent
external resources simplifies processing while allowing a rich
set of information to be maintained on each resource.
\subsection{Internal References
\label{internal-references}}
A single element is provided to support internal references to
other elements within an XBEL instance.
\subsubsection{The \element{alias} Element
\label{element-alias}}
\paragraph*{Attributes}
Only one attribute is needed for \element{alias}, and is
required to identify the link referent.
\begin{definitions}
\term{\attribute{ref}, \emph{required}}
IDREF value which refers to a \element{bookmark} or
\element{folder} element, or the document \element{xbel}
element.
\end{definitions}
\paragraph*{Processing Expectations}
Software which presents bookmarks in a user interface should
distinguish aliases from other bookmarks visually, but
otherwise allow examination of the referent transparently.
Netscape Navigator does this by presenting the bookmark title
in an italic font; the appropriate visual distrinction is
likely to be dependent on other aspects of the user
interface.
Outside of user interface considerations, treatment of aliases
is application-specific. However, some guidance may prove
useful. When encountering an \element{alias}, an application
should only need to traverse the \element{alias} and process
the referent if that referent would not otherwise be
processed, otherwise, the \element{alias} may usually be
ignored. This should become an issue only when the
application is processing a portion of the bookmark hierarchy
rather than the complete tree.
\paragraph*{Rationale}
Netscape Navigator and Microsoft Internet Explorer bookmarks
can include ``aliases'' to other nodes in the hierarchical
structure. Navigator supports only aliases to bookmark nodes,
while Internet Explorer also supports aliases to folders.
Navigator's format simply adds the attribute
\attribute{aliasid} to nodes which are referred to be aliases,
and the attribute \attribute{aliasof} to the actual alias.
All other information is duplicated for each alias of the
primary bookmark entry. XBEL uses a distinct element and the
ID/IDREF mechanism provided by XML to avoid redundency and
support validation.
\section{DTD Structure
\label{dtd-structure}}
This section discusses how the DTD itself is organized. This is
mostly of interest to the maintainers of XBEL and any descendent
document types that may be defined in the future.
\subsection{Use of Parameter Entities
\label{parameter-entities}}
Limited use of parameter entities is made in the XBEL DTD. The
suffix-notation is adopted from the ``XMLspec'' DTD report
\cite{w3c-xmlspec}. Specifically, the \samp{.mix} suffix is used
for entities which define repeatable-or groups of elements, and
\samp{.att} is used for entities which define attributes.
\subsubsection{The \paramentity{metadata.mix} Entity
\label{entity-metadata.mix}}
\subsubsection{The \paramentity{nodes.mix} Entity
\label{entity-nodes.mix}}
The \paramentity{nodes.mix} entity lists the element types which
may be used to form the nodes of the hierarchical data structure
described by an XBEL instance. This entity species a mixture of
\element{bookmark}, \element{folder}, \element{separator} and
\element{alias} elements.
\subsubsection{The \paramentity{node.att} Entity
\label{entity-node.att}}
This entity is used to define attributes for element types which
hold the real content of the bookmark data. It is used on the
\element{bookmark} and \element{folder} elements. It defines
the optional \attribute{added} and \attribute{id} attributes.
\subsubsection{The \paramentity{url.att} Entity
\label{entity-url.att}}
This entity defines the attributes which are available on
elements which refer to specific resources. In XBEL 1.0 and
1.1, this is only used on the \element{bookmark} element. It
defines a required \attribute{href} attribute and the optional
attributes \attribute{modified} and \attribute{visited}.
\subsection{Extending the DTD
\label{extending}}
Extensibility of XBEL relies on three foundations: XML namespaces
and the acceptability of well-formed instances, localized
parameters entities, and the simplicity of the DTD itself.
The primary expectation for DTD extensions is that new elements
and attributes will be introduced and defined using XML
namespaces. Though still in the stage of a working draft within
the W3C, namespaces offer the most flexible extension mechanism
available for XML-based markup languages used in wide-spread
deployment. Until validation requirements in the context of
namespaces are more clearly defined, XBEL instances using
namespaces can apply well-formedness rules as a vehicle for
partial validation.
More traditional document type extension uses parameter entities
reserved for localization. The XBEL public text provides three
such entities as ``hooks'' to allow local customization. For each
of the parameter entities described in Section
\ref{parameter-entities}, ``Use of Parameter Entities,'' a
\paramentity{local.\var{name}} variant is declared and used in the
definition of each of the entities described above. This is less
flexible than the namespace approach, but allows a new document
type to be created which can be used for validation with current
tools without having to create a new public text from scratch.
The third foundation for extensibility, the simplicity of the DTD,
can be effectively used only by taking a ``steal this code''
approach to reuse. XBEL is sufficiently simple that it can easily
be understood in its entirety, and a variant document type created
by crafting a new public text.
\subsection{General Entities
\label{general-entities}}
The XBEL DTD defines no general entities.
\paragraph*{Rationale}
Since XBEL is intended as an interchange format for software and
not as an authoring format, there is no need to support typical
entities used to enter special characters. Entities which do
not correspond to Unicode characters are too
application-specific to predict meaningfully
\cite{unicode20,unicode21}.
\appendix
\section{Public Text
\label{public-text}}
This section contains the entire public text of the XBEL DTD
corresponding to the Formal Public Identifier presented in Section
\ref{formal-ident}. No additional external entities are
referenced.
\begin{longexample}
\verbatiminput{../xbel.dtd}
\end{longexample}
\nocite{*}
\bibliographystyle{alpha}
\bibliography{xbel}
\end{document}
PyXML-0.8.2/demo/xbel/README 0100644 0000764 0000144 00000001560 07263756175 014472 0 ustar martin users This directory contains various scripts for processing XBEL, the XML
Bookmark Exchange Language proposed by Mark Hammond on the XML-SIG.
Scripts are provided to convert the bookmark files for various Web
browsers to XBEL, and to render an XBEL document as HTML.
xbel-1.1.dtd The Document Type Definition for XBEL 1.1.
xbel-1.0.dtd The Document Type Definition for XBEL 1.0.
bookmark.py Contains the Bookmarks and Bookmark classes, which represent
a bookmark file, and can be output in any of the
browser formats, or in XBEL.
ns_parse.py A class that parses Netscape bookmark files.
msie_parse.py A class that parses Internet Explorer bookmark files.
adr_parse.py A class that parses Opera bookmark files.
lynx_parse.py A class that parses Lynx bookmark files.
xbel_parse.py A class that parses an XBEL input file and can output it
in any of the other formats.
PyXML-0.8.2/demo/xbel/adr_parse.py 0100644 0000764 0000144 00000006016 07517567465 016131 0 ustar martin users #!/usr/bin/env python
"""
Small utility to parse Opera bookmark files.
Written by Lars Marius Garshol
"""
import string,bookmark,time
# --- Constants
short_months={"Jan":"01","Feb":"02","Mar":"03","Apr":"04","May":"05",
"Jun":"06","Jul":"07","Aug":"08","Sep":"09","Oct":"10",
"Nov":"11","Dec":"12"}
# --- Parsing exception
class OperaParseException(Exception):
pass
# --- Methods
def readfield(infile, fieldname, required = 1):
line = infile.readline()
linelength = len(line)
pos = string.find(line,fieldname+"=")
if pos == -1 and required:
raise OperaParseException("Field '%s' missing" % fieldname)
if pos == -1 and required == 0:
infile.seek(-linelength, 1)
return string.rstrip(line[pos+len(fieldname)+1:])
def swallow_rest(infile):
"Reads input until first blank line."
while 1:
line=infile.readline()
if line=="" or line=="\n" or line=="\015\012": break
def parse_date(date):
# CREATED=904923783 (Fri Sep 04 17:43:03 1998)
# VISITED=0 (?)
if date=="":
return None
lp=string.find(date,"(")
rp=string.find(date,")")
if lp==-1 or rp==-1:
if string.find(date," ")!=-1:
raise OperaParseException("Can't handle this date: %s" % `date`)
t=time.localtime(string.atoi(date))
return "%s%s%s" % (t[0],string.zfill(t[1],2),string.zfill(t[2],2))
if date[lp:rp+1]=="(?)":
return None
month=short_months[date[lp+5:lp+8]]
day=date[lp+9:lp+11]
year=date[rp-4:rp]
return "%s%s%s" % (year,month,day)
def parse_adr(filename):
bms=bookmark.Bookmarks()
infile=open(filename)
version=infile.readline()
while 1:
line=infile.readline()
if line=="": break
line=string.rstrip(line)
if line=="#FOLDER":
name=readfield(infile,"NAME")
created=parse_date(readfield(infile,"CREATED"))
parse_date(readfield(infile, "VISITED", 0)) # just throw this away
order = readfield(infile, "ORDER", 0)
swallow_rest(infile)
bms.add_folder(name,created)
elif line=="#URL":
name=readfield(infile,"NAME")
url=readfield(infile,"URL")
created=parse_date(readfield(infile,"CREATED"))
visited=parse_date(readfield(infile, "VISITED", 0))
order = readfield(infile, "ORDER", 0)
swallow_rest(infile)
bms.add_bookmark(name,created,visited,None,url)
elif line=="-":
bms.leave_folder()
return bms
# --- Test-program
if __name__ == '__main__':
import sys
if len(sys.argv)<2 or len(sys.argv)>3:
print
print "A simple utility to convert Opera bookmarks to XBEL."
print
print "Usage: "
print " adr_parse.py []"
sys.exit(1)
bms=parse_adr(sys.argv[1])
if len(sys.argv)==3:
out=open(sys.argv[2],"w")
bms.dump_xbel(out)
out.close()
else:
bms.dump_xbel()
# Done
PyXML-0.8.2/demo/xbel/bookmark.py 0100644 0000764 0000144 00000026306 07613237634 015767 0 ustar martin users """
Classes to store bookmarks and dump them to XBEL.
"""
import sys,string,types
from xml.sax.saxutils import escape
# --- Class for bookmark container
class Bookmarks:
def __init__(self, info=None, id=None, title=None):
self.folders=[]
self.folder_stack=[]
self.desc = "No description"
self.info = info
self.id = id
self.title = title
def add_folder(self, name, added=None):
nf=Folder(name, added)
if self.folder_stack==[]:
self.folders.append(nf)
else:
self.folder_stack[-1].add_child(nf)
self.folder_stack.append(nf)
return nf
def add_bookmark(self,name=None,
added=None, visited=None, modified=None,
href=None, desc = None):
nb=Bookmark(name,added,visited,modified,href, desc = desc)
if self.folder_stack!=[]:
self.folder_stack[-1].add_child(nb)
else:
self.folders.append(nb)
return nb
def add_separator(self):
s = Separator()
if self.folder_stack!=[]:
self.folder_stack[-1].add_child(s)
else:
self.folders.append(s)
return s
def leave_folder(self):
if self.folder_stack!=[]:
del self.folder_stack[-1]
def update_ids(self):
ids = {}
aliases = []
for folder in self.folders:
folder.update_ids(ids, aliases)
for alias in aliases:
alias.update_link(ids)
def dump_xbel(self,out=sys.stdout):
if self.id:
ID = ' id="%s"' % self.id
else:
ID = ""
out.write('\n'
'\n'
'\n'
% ID
)
if self.title:
out.write(" %s\n" % encode(self.title))
if self.info:
out.write(" %s\n" % encode(self.info))
out.write(" %s\n" % (esc_enc(self.desc),) )
for folder in self.folders:
folder.dump_xbel(out)
out.write("\n")
def dump_adr(self,out=sys.stdout):
out.write("Opera Hotlist version 2.0\n\n")
for folder in self.folders:
folder.dump_adr(out)
def dump_netscape(self,out=sys.stdout):
out.write("\n")
out.write("\n")
# Mozilla recognizes the content-type declaration; let's hope
# Netscape 4 is not bothered by it
out.write('\n')
if self.title:
out.write("" + encode(self.title) + "\n")
else:
out.write("Bookmarks\n")
out.write("
" + encode(self.desc) + "
\n\n")
out.write("
\n")
for folder in self.folders:
folder.dump_netscape(out)
out.write("
\n")
# Lynx uses multiple bookmark files; each folder will be written to a
# different file.
def dump_lynx(self, path):
import os
for folder in self.folders:
# First, figure out a reasonable filename for this folder
filename = string.replace(folder.title, ' ', '_') + '.html'
# Open a file for the top-level folders
output = open( os.path.join(path, filename), 'w')
print 'folder title:', folder.title, filename
output.write('
\n%s\n\n'
% (folder.title,) )
output.write('
\n
\n')
folder.dump_lynx(output)
output.close()
# --- Superclass for folder and bookmarks
class Node:
def __init__(self, name, added=None,
visited=None, modified=None, id=None, desc=None):
self.title = name
self.added = added
self.visited = visited
self.modified = modified
self.id = id
self.desc = desc
def update_ids(self, ids, aliases):
if self.id:
while ids.has_key(self.id):
# Duplicate ID
self.id = self.id + '0'
ids[self.id] = self
def gen_id(self, ids):
self.id = 'X'+str(id(self))
self.update_ids(ids, [])
# --- Class for folders
class Folder(Node):
def __init__(self, name, added = None, info = None, id=None,
folded = 'yes', icon = None, toolbar = 'no', desc=None):
Node.__init__(self, name, added=added, id=None,desc=desc)
self.children=[]
self.info = None
self.folded = None
self.icon = None
self.toolbar = None
def add_child(self,child):
self.children.append(child)
def update_ids(self, ids, aliases):
Node.update_ids(self, ids, aliases)
for node in self.children:
node.update_ids(ids, aliases)
def is_folded(self):
# folded defaults to yes
return self.folded is None or self.folded == 'yes'
def dump_xbel(self,out):
if self.id:
ID = ' id="%s"' % self.id
else:
ID = ""
if self.added:
added = ' added="%s"' % self.added
else:
added = ""
if self.folded is not None:
folded = ' folded="%s"' % self.folded
else:
folded = ""
if self.icon is not None:
icon = ' icon="%s"' % self.icon
else:
icon = ""
if self.toolbar is not None:
toolbar = ' toolbar="%s"' % self.toolbar
else:
toolbar = ""
out.write(" \n" % (ID, added, folded, icon, toolbar))
out.write(" %s\n" % esc_enc(self.title) )
if self.info:
out.write(" %s\n" % encode(self.info))
if self.desc:
out.write(" %s\n" % encode(self.desc))
for child in self.children:
child.dump_xbel(out)
out.write(" \n")
def dump_adr(self,out):
out.write("#FOLDER\n")
out.write("\tNAME=%s\n" % self.title)
out.write("\tADDED=%s\n" % "0 (?)")
out.write("\tVISITED=%s\n" % "0 (?)")
out.write("\tORDER=-1\n")
out.write("\n")
for child in self.children:
child.dump_adr(out)
out.write("\n")
out.write("-\n")
def dump_netscape(self,out):
if self.id:
ID = ' ID="%s"' % self.id
else:
ID = ""
if self.is_folded():
folded = " FOLDED"
else:
folded = ""
if self.added:
added = ' ADD_DATE="%s"' % self.added
else:
added = ""
out.write("
%s
\n" %
(folded,added,ID,encode(self.title)))
if self.desc:
out.write("
%s\n" %
(encode(self.desc)))
out.write("
\n")
for child in self.children:
child.dump_netscape(out)
out.write("
\n")
def dump_lynx(self, out):
out.write("
%s
\n" % self.title)
out.write(" \n")
for child in self.children:
child.dump_lynx(out)
# Mustn't write the closing , because Lynx will add it
# when it reads the bookmark file.
##out.write("
%s\n" % (self.href, self.title) )
# --- Class for separators
class Separator(Node):
def __init__(self):
Node.__init__(self, None)
def dump_xbel(self, out):
out.write(' \n')
def dump_netscape(self, out):
out.write(" \n")
# --- Class for separators
class InvalidReference(Exception):
pass
class Alias(Node):
def __init__(self, aliased_to):
Node.__init__(self, None)
if isinstance(aliased_to, Node):
self.aliased_to = aliased_to
self.ref = None
else:
self.aliased_to = None
self.ref = aliased_to
def update_ids(self, ids, aliases):
aliases.append(self)
def update_link(self, ids):
if self.aliased_to:
if self.aliased_to.id is None:
self.aliased_to.gen_id(ids)
self.ref = self.aliased_to.id
else:
try:
self.aliased_to = ids[self.ref]
except KeyError:
raise InvalidReference, self.ref
def dump_xbel(self, out):
out.write(' \n' % self.ref)
# --- helper functions
try:
types.UnicodeType
except AttributeError:
def encode(str, encoding = "utf-8"):
# Can't do proper recoding in Python 1.5
return str
else:
def encode(str, encoding = "utf-8"):
if type(str) == types.UnicodeType:
return str.encode(encoding)
return str
def esc_enc(str):
return encode(escape(str))
PyXML-0.8.2/demo/xbel/lynx_parse.py 0100644 0000764 0000144 00000003611 07413602741 016331 0 ustar martin users #!/usr/bin/env python
#
# lynx_parse.py :
# Read a list of Lynx bookmark files, specified on the command line,
# and outputs the corresponding XBEL document.
#
# Sample usage: ./lynx_parse.py ~/bookmarks/
# (The script requires the path to the directory where your bookmark files
# are stored.)
#
import bookmark
import re
def parse_lynx_file(bms, input):
"""Convert a Lynx 2.8 bookmark file to XBEL, reading from the
input file object, and write to the output file object."""
# Read the whole file into memory
data = input.read()
# Get the title
m = re.search("(.*?)", data, re.IGNORECASE)
if m is None: title = "Untitled"
else: title = m.group(1)
bms.add_folder( title )
hrefpat = re.compile( r"""^ \s*
\s*
[^"]* )" \s*>
(?P .*? ) """,
re.IGNORECASE| re.DOTALL | re.VERBOSE | re.MULTILINE)
pos = 0
while 1:
m = hrefpat.search(data, pos)
if m is None: break
pos = m.end()
url, name = m.group(1,2)
bms.add_bookmark( name, href = url)
bms.leave_folder()
if __name__ == '__main__':
import sys, glob
if len(sys.argv)<2 or len(sys.argv)>3:
print
print "A simple utility to convert Lynx bookmarks to XBEL."
print
print "Usage: "
print " lynx_parse.py []"
sys.exit(1)
bms = bookmark.Bookmarks()
# Determine the owner on Unix platforms
import os, pwd
uid = os.getuid()
t = pwd.getpwuid( uid )
bms.owner = t[4]
glob_pattern = os.path.join(sys.argv[1], '*.html')
file_list = glob.glob( glob_pattern )
for file in file_list:
input = open(file)
parse_lynx_file(bms, input)
if len(sys.argv)==3:
out=open(sys.argv[2],"w")
bms.dump_xbel(out)
out.close()
else:
bms.dump_xbel()
# Done
PyXML-0.8.2/demo/xbel/msie_parse.py 0100644 0000764 0000144 00000005705 07534565152 016312 0 ustar martin users #!/usr/bin/env python
"""
Small utility to convert MSIE favourites to an object structure.
Originally written by Fredrik Lundh.
Modified by Lars Marius Garshol
2-17-2002 tbp Now closes folder when its traverse is done. Also works
with current IE shortcut format, which can differ from the format
that was assumed here.
"""
import bookmark,os,string
DIR = "Favoritter" # Norwegian version
#USRDIR = os.environ["USERPROFILE"] # NT version
USRDIR = r"c:\windows" # 95 version
class MSIE:
# internet explorer
def __init__(self,bookmarks, path):
self.bms=bookmarks
self.root = None
self.path = path
self.__walk()
def __walk(self, subpath=[]):
# traverse favourites folder
path = os.path.join(self.path, string.join(subpath, os.sep))
for file in os.listdir(path):
fullname = os.path.join(path, file)
if os.path.isdir(fullname):
self.bms.add_folder(file,None)
self.__walk(subpath + [file])
self.bms.leave_folder()
else:
url = self.__geturl(fullname)
if url:
self.bms.add_bookmark(os.path.splitext(file)[0],None,
None,None,url)
def __geturl(self, file):
try:
fp = open(file)
#if fp.readline() != "[InternetShortcut]\n":
# return None
while 1:
line=fp.readline()
if not line:
return None
if line=="[InternetShortcut]\n":
s = fp.readline()
if not s:
break
if s[:4] == "URL=":
fp.close()
return s[4:-1]
elif line=="[DEFAULT]\n":
s = fp.readline()
if not s:
break
if s[:8] == "BASEURL=":
fp.close()
return s[8:-1]
except IOError:
return ''
fp.close()
return ''
# --- Testprogram
if __name__ == '__main__':
import sys
if len(sys.argv)>1:
path = sys.argv[1]
else:
try:
import win32api, win32con
except ImportError:
print "The win32api module is not available on this system"
print "so we can't automatically find your favorites folder."
print "Please re-run this program specifiying the location of your"
print "favorites folder on the command line."
sys.exit(1)
keyname = r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
hkey = win32api.RegOpenKey(win32con.HKEY_CURRENT_USER, keyname)
path, pathtype = win32api.RegQueryValueEx(hkey, "Favorites")
assert pathtype == win32con.REG_SZ
msie=MSIE(bookmark.Bookmarks(), path)
msie.bms.dump_xbel()
PyXML-0.8.2/demo/xbel/ns_parse.py 0100644 0000764 0000144 00000011633 07517567465 016004 0 ustar martin users #!/usr/bin/env python
"""
Small utility that parses Netscape bookmarks.
"""
# TODO:
# LAST_CHARSET: put in ...
# H3:LAST_MODIFIED: Put in XBEL 1.2?
# Cross references?
# Descriptions
from xml.sax import sax2exts,handler
import bookmark
import string, htmlentitydefs
# --- SAX handler for Netscape bookmarks
class NetscapeHandler(handler.ContentHandler):
def __init__(self):
self.bms=bookmark.Bookmarks()
self.cur_elem = None
self.added = None
self.href = None
self.visited = None
self.modified = None
self.latest = None
self.desc = ""
def startElement(self,name,attrs):
name = string.lower( name )
d = {}
for key, value in attrs.items():
d[ string.lower(key) ] = value
## print 'start', name, d
if name=="h3":
self.cur_elem="h3"
if d.has_key("folded"):
self.folded = "yes"
else:
self.folded = "no"
self.id = d.get('id')
self.added= d.get('add_date',"")
self.modified = d.get('last_modified', "")
folder = self.bms.add_folder('', None)
folder.id = self.id
folder.folded = self.folded
folder.added = self.added
self.latest = folder
elif name=="a":
self.cur_elem="a"
self.bookmark = ""
if d.has_key('add_date'): self.added=d["add_date"]
else: self.added = None
if d.has_key('last_visit'): self.visited=d["last_visit"]
else: self.visited = None
if d.has_key('last_modified'): self.modified=d["last_modified"]
else: self.modified = None
self.url=d["href"]
elif name=='title':
self.cur_elem = 'title'
self.bms.title = ""
elif name=='h1':
self.cur_elem = 'h1'
self.bms.desc = ""
elif name=='hr':
self.bms.add_separator()
elif name=='meta':
if d.has_key('http-equiv') and \
string.lower(d['http-equiv'])=='content-type':
value = string.split(d['content'], "charset=")
if len(value) == 2:
the_parser.setProperty(handler.property_encoding, value[1])
elif name in ('dt','dl'):
if self.desc and not self.latest.desc:
self.latest.desc = self.desc
self.desc = ""
self.curr_elem = ''
elif name=='dd':
self.cur_elem = 'dd'
self.desc = ""
def characters(self,data):
## print 'char', self.cur_elem, data
if self.cur_elem=="h3":
self.latest.title+=data
elif self.cur_elem=="a":
self.bookmark = self.bookmark+data
elif self.cur_elem=="title":
self.bms.title = self.bms.title + data
elif self.cur_elem=="h1":
self.bms.desc = self.bms.desc + data
elif self.cur_elem=="dd":
self.desc = self.desc + data
def skippedEntity(self, name):
self.characters(htmlentitydefs.entitydefs[name])
def endElement(self,name):
name = string.lower( name )
## print 'end', name
if name=="a":
self.latest = self.bms.add_bookmark(self.bookmark,
added = self.added,
visited = self.visited,
modified = self.modified,
href = self.url)
elif name=="h3":
self.cur_elem=None
elif name=="dl":
self.bms.leave_folder()
elif name == self.cur_elem:
self.cur_elem=None
def endDocument(self):
if self.desc and not self.latest.desc:
self.latest.desc = self.desc
# --- Test-program
if __name__ == '__main__':
import sys
if len(sys.argv)<2 or len(sys.argv)>3:
print
print "A simple utility to convert Netscape bookmarks to XBEL."
print
print "Usage: "
print " ns_parse.py []"
sys.exit(1)
ns_handler=NetscapeHandler()
the_parser = sax2exts.SGMLParserFactory.make_parser()
the_parser.setContentHandler(ns_handler)
# For Netscape 4, default to Latin-1
the_parser.setProperty(handler.property_encoding, "iso-8859-1")
file = open(sys.argv[1], 'r')
the_parser.parse(file)
bms = ns_handler.bms
if len(sys.argv)==3:
out=open(sys.argv[2],"w")
bms.dump_xbel(out)
out.close()
else:
bms.dump_xbel()
# Done
## ns_handler=NetscapeHandler()
## p=saxexts.SGMLParserFactory.make_parser()
## p.setDocumentHandler(ns_handler)
## p.parseFile(open(r"/home/amk/.netscape/bookmarks.html"))
## ns_handler.bms.dump_xbel()
PyXML-0.8.2/demo/xbel/xbel-1.0.dtd 0100644 0000764 0000144 00000005252 07547107337 015532 0 ustar martin users
PyXML-0.8.2/demo/xbel/xbel-1.1.dtd 0100644 0000764 0000144 00000006330 07547107337 015531 0 ustar martin users
PyXML-0.8.2/demo/xbel/xbel2html.py 0100644 0000764 0000144 00000004651 07517567465 016075 0 ustar martin users #! /usr/bin/env python
"""
A simple XBEL to HTML converter written with SAX.
"""
# Limitations: will screw up if a folder lacks a 'title' element.
# no checking of the command-line args
import sys
from xml.sax import make_parser,saxlib,saxutils
# --- HTML templates
top=\
"""
%s
%s
"""
bottom=\
"""
Converted from XBEL by xbel2html.
"""
# --- DocumentHandler
class XBELHandler(saxlib.ContentHandler):
def __init__(self,writer=sys.stdout,encoding='utf-8'):
self.stack=[]
self.writer=writer
self.last_url=None
self.inside_ul=0
self.level=0
self.encoding=encoding
def startElement(self,name,attrs):
self.stack.append(name)
self.data = ''
if name=="bookmark":
self.last_url=attrs["href"].encode(self.encoding)
def characters(self,data):
self.data += data.encode(self.encoding)
def endElement(self,name):
data = self.data
if self.stack[-1]=="title" and self.stack[-2]=="xbel":
self.writer.write(top % (data,self.encoding,data))
self.state=None
if self.stack[-1]=="desc" and self.stack[-2]=="xbel":
self.writer.write("
%s
\n" % data)
if self.stack[-1]=="title" and self.stack[-2]=="bookmark":
if not self.inside_ul:
self.inside_ul=1
self.writer.write("
\n")
self.writer.write('
%s. \n' %
(self.last_url,data))
if self.stack[-1]=="desc" and self.stack[-2]=="bookmark":
self.writer.write(data+"\n\n")
if self.stack[-1]=="title" and self.stack[-2]=="folder":
self.writer.write("
%s\n" % data)
self.writer.write("
\n")
self.inside_ul=1
del self.stack[-1]
if name=="folder":
self.writer.write("
\n")
def endDocument(self):
self.writer.write("
\n")
self.writer.write(bottom)
# --- Main program
if __name__ == '__main__':
p=make_parser()
p.setContentHandler(XBELHandler())
p.setErrorHandler(saxutils.ErrorPrinter())
p.parse(sys.argv[1])
PyXML-0.8.2/demo/xbel/xbel_parse.py 0100644 0000764 0000144 00000007501 07517567465 016315 0 ustar martin users #!/usr/bin/env python
"""
A class to parse an XBEL file and produce a Bookmarks instance.
If executed as a script, this module will read an XBEL file from
standard input, produce the corresponding Bookmarks instance, and dump
it to standard output in a selected format.
"""
import bookmark
import string
from xml.sax import saxlib,make_parser
class XBELHandler(saxlib.ContentHandler):
def __init__(self):
self.bms = bookmark.Bookmarks()
self.entered_folder = self.entered_bookmark = 0
def startElement(self, name, attrs):
self.cur_elem = name
# print name, attrs
if name == 'folder':
self.entered_folder = 1
self.id = attrs.get('id')
self.added = attrs.get('added')
self.folded = attrs.get('folded')
self.icon = attrs.get('icon')
self.toolbar = attrs.get('toolbar')
elif name == 'title':
self.title = ""
elif name == 'desc':
self.desc = ""
elif name == 'bookmark':
self.entered_bookmark = 1
self.title = self.href = ""
self.added = self.visited = self.modified = ""
if attrs.has_key('href'):
self.href = attrs['href']
if attrs.has_key('added'):
self.added = attrs['added']
if attrs.has_key('visited'):
self.visited = attrs['visited']
if attrs.has_key('modified'):
self.modified = attrs['modified']
def characters(self, data):
if self.cur_elem in ['title', 'desc']:
attr = string.lower(self.cur_elem)
value = getattr(self, attr)
setattr(self, attr, value + data)
def endElement(self, name):
self.cur_elem = None
if name == 'folder':
self.bms.leave_folder()
self.entered_folder = 0
elif name == 'desc':
self.bms.desc = self.desc
elif name == 'title':
if self.entered_folder:
folder = self.bms.add_folder(self.title)
folder.id = self.id
folder.added = self.added
folder.folded = self.folded
folder.icon = self.icon
folder.toolbar = self.toolbar
self.entered_folder = 0
elif not self.entered_bookmark:
self.bms.title = self.title
elif name == 'bookmark':
self.entered_folder = 0
self.entered_bookmark = 0
if self.added == "": self.added = None
if self.visited == "": self.visited = None
if self.modified == "": self.modified = None
self.bms.add_bookmark(self.title, self.added, self.visited, self.modified, self.href)
elif name == 'separator':
self.bms.add_separator()
if __name__ == '__main__':
import sys, getopt
opts, args = getopt.getopt(sys.argv[1:], '',
['opera', 'netscape', 'lynx=', 'msie', 'xbel'] )
if len(args):
print 'xbel_parse only reads from standard input'
sys.exit(1)
if len(opts)>1 or len(opts)==0:
print 'You must specify a single output format when running xbel_parse'
print 'Available formats: --opera, --netscape, --msie, --lynx, --xbel'
print ' --lynx : For Lynx, a path to the directory where'
print ' the output bookmark files should be written'
sys.exit(1)
xbel_handler = XBELHandler()
p=make_parser()
p.setContentHandler( xbel_handler )
p.parse( sys.stdin )
bms = xbel_handler.bms
mode, arg = opts[0]
if mode == '--opera': bms.dump_adr()
elif mode == '--lynx': bms.dump_lynx(arg)
elif mode == '--netscape': bms.dump_netscape()
elif mode == '--msie': bms.dump_msie()
elif mode == '--xbel': bms.dump_xbel()
PyXML-0.8.2/demo/xmlproc/ 0040755 0000764 0000144 00000000000 07614726123 014333 5 ustar martin users PyXML-0.8.2/demo/xmlproc/dtds/ 0040755 0000764 0000144 00000000000 07614726123 015271 5 ustar martin users PyXML-0.8.2/demo/xmlproc/dtds/xbel-1.0.dtd 0100644 0000764 0000144 00000005247 06660162333 017216 0 ustar martin users
PyXML-0.8.2/demo/xmlproc/dtds/xsa.dtd 0100644 0000764 0000144 00000001163 06660162333 016554 0 ustar martin users
PyXML-0.8.2/demo/xmlproc/catalog.soc 0100644 0000764 0000144 00000001056 06660162324 016447 0 ustar martin users
--
DEMO CATALOG for xmlproc
This is just a demonstration catalog file that resolves the public
identifiers of the DTDs that come with the parser
--
PUBLIC "-//LM Garshol//DTD XML Software Autoupdate 1.0//EN//XML"
"dtds/xsa.dtd"
PUBLIC "+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML"
"dtds/xbel-1.0.dtd"
-- If we can't find a system identifier for the public identifier here,
then go to James Tauber's public catalog --
DELEGATE "" "http://www.schema.net/public-text/catalog.soc" PyXML-0.8.2/demo/xmlproc/doctree.py 0100644 0000764 0000144 00000003623 07413602741 016327 0 ustar martin users """
A very simple tree model for XML documents. Elements are represented as
triples (name, attribute dictionary, content list), and the entire document
is represented by the document element.
"""
import types
from xml.parsers.xmlproc import xmlproc
# --- Tree-building functions
def build_tree(sysid):
"Builds a doctree and returns it."
class BuilderApp(xmlproc.Application):
"The actual tree builder."
def __init__(self):
self.root=None
self.current_stack=[]
def handle_start_tag(self,name,attrs):
if self.root==None:
self.current_stack.append([])
self.root=(name,attrs,self.current_stack[-1])
else:
list=[]
self.current_stack[-1].append(name,attrs,list)
self.current_stack.append(list)
def handle_data(self,data,start,end):
if self.root!=None:
self.current_stack[-1].append(data[start:end])
def handle_end_tag(self,name):
del self.current_stack[-1]
builder=BuilderApp()
parser=xmlproc.XMLProcessor()
parser.set_application(builder)
parser.parse_resource(sysid)
return builder.root
# --- Utility functions
def get_element(parent,child_type_name):
"Locates the first child element with the given name inside an element."
for child in parent[2]:
if type(child)==types.TupleType and child[0]==child_type_name:
return child
def get_elements(parent,child_type_name):
"Locates the child elements with the given name inside an element."
list=[]
for child in parent[2]:
if type(child)==types.TupleType and child[0]==child_type_name:
list.append(child)
return list
def get_pcdata(parent):
"""Picks out the PCDATA contents of the element, under the assumption
that all the contents are PCDATA."""
return parent[2][0]
PyXML-0.8.2/demo/xmlproc/dtd2schema.py 0100644 0000764 0000144 00000022366 07534565152 016735 0 ustar martin users #!/usr/bin/python
"""
This script converts DTDs to XML Schemas, according to the 20000407 WD.
It can do simple reverse-engineering of attribute groups.
"""
# Todo
# - make better names for attrgroups?
# - make a SchemaWriter class (to hold common references)
# - start doing reverse engineering to create modelGroups?
from xml.parsers.xmlproc import xmldtd
import sys, types, os.path, string
usage = \
"""
Usage:
python dtd2schema.py []
Input file names can be URLs.
If the output file name is omitted, it will be inferred from the
input file name. Note that this inference does not work for URLs.
"""
version = "0.2"
# ===== UTILITY FUNCTIONS
class CountingDict:
def __init__(self):
self._items = {}
def count(self, item):
try:
self._items[item] = self._items[item] + 1
except KeyError:
self._items[item] = 1
def clear(self):
self._items = {}
def keys(self):
return self._items.keys()
def __getitem__(self, item):
return self._items[item]
def __delitem__(self, item):
del self._items[item]
class AttributeInfo:
"""This class holds information about reverse-engineered attribute
groupings."""
def __init__(self):
self._shared_attrs = {}
self._shared_attrs_on_elem = {}
self._count = CountingDict()
self._groupnames = {}
def count(self, attrname):
self._count.count(attrname)
def new_attr(self, elemname, attr):
attrname = attr.get_name()
self._count.count(attrname)
if self._shared_attrs.has_key(attrname):
shared = self._shared_attrs[attrname]
if shared != None and not compare_attrs(shared, attr):
self._shared_attrs[attrname] = None
else:
self._shared_attrs[attrname] = attr
def remove_single_attributes(self):
"Removes attributes that only occurred once."
for attrname in self._shared_attrs.keys():
if self._shared_attrs.get(attrname) != None:
if self._count[attrname] < 2:
self._shared_attrs[attrname] = None
self._count.clear()
def find_groups(self, elem):
shared = tuple(filter(self._shared_attrs.get, elem.get_attr_list()))
self._shared_attrs_on_elem[elem.get_name()] = shared
if shared:
self._count.count(shared)
def remove_single_groups(self):
"Removes groups that only occurred once."
for group in self._count.keys():
if self._count[group] < 2:
del self._count[group]
def get_groups(self):
return self._count.keys()
def get_attribute(self, name):
return self._shared_attrs[name]
def get_shared_attrs_on_elem(self, elemname):
return self._shared_attrs_on_elem[elemname]
def make_name(self, group):
name = "group" + str(len(self._groupnames) + 1)
self._groupnames[group] = name
return name
def get_group_name(self, group):
return self._groupnames[group]
def escape_attr_value(value):
value = string.replace(value, '&', '&')
value = string.replace(value, '"', '"')
return string.replace(value, '<', '<')
# ===== REVERSE ENGINEERING
def compare_attrs(attr1, attr2):
return attr1.get_name() == attr2.get_name() and \
attr1.get_type() == attr2.get_type() and \
attr1.get_decl() == attr2.get_decl() and \
attr1.get_default() == attr2.get_default()
def find_attr_groups(dtd):
# first pass: find attributes that occur more than once
attrinfo = AttributeInfo()
for elemname in dtd.get_elements():
elem = dtd.get_elem(elemname)
for attrname in elem.get_attr_list():
attrinfo.new_attr(elemname, elem.get_attr(attrname))
attrinfo.remove_single_attributes()
# second pass: group the recurring attributes
for elemname in dtd.get_elements():
elem = dtd.get_elem(elemname)
attrinfo.find_groups(elem)
attrinfo.remove_single_groups()
return attrinfo
# ===== COMPONENT FUNCTIONS
def write_attribute_group(out, group, attrinfo):
groupname = attrinfo.make_name(group)
out.write(' \n' % groupname)
for attrname in group:
write_attr(out, attrinfo.get_attribute(attrname))
out.write(' \n')
declmap = {"#REQUIRED" : "required",
"#IMPLIED" : "optional",
"#DEFAULT" : "default",
"#FIXED" : "fixed" }
def write_attr(out, attr):
value = attr.get_default()
if value == None:
value = ''
else:
value = ' value="%s"' % escape_attr_value(value)
attrtype = attr.get_type()
if type(attrtype) == types.ListType:
out.write(' \n' %
(attr.get_name(), declmap[attr.get_decl()], value))
out.write(' \n')
for token in attrtype:
out.write(' \n' % token)
out.write(' \n')
out.write(' \n')
else:
out.write(' \n' %
(attr.get_name(), attrtype, declmap[attr.get_decl()],
value))
def write_attributes(out, elem, attrinfo):
attrnames = elem.get_attr_list()
shared = attrinfo.get_shared_attrs_on_elem(elem.get_name()) or []
for attrname in attrnames:
if not attrname in shared:
write_attr(out, elem.get_attr(attrname))
if shared:
out.write(' \n' %
attrinfo.get_group_name(group))
def write_element_type(out, elem, attrinfo):
cm = elem.get_content_model()
if cm == ('', [('#PCDATA', '')], ''):
if elem.get_attr_list() == []:
out.write(' \n')
else:
out.write(' \n')
write_attributes(out, elem, attrinfo)
out.write(' \n')
return
content = ''
if cm == ("", [], ""):
content = ' content="empty"'
elif cm != None and cm[1][0][0] == "#PCDATA":
content = ' content="mixed"'
out.write(' \n' % content)
if cm == None:
out.write(' \n')
elif cm != ("", [], ""):
write_cm(out, cm)
write_attributes(out, elem, attrinfo)
out.write(' \n')
def write_cm(out, cm):
(sep, cps, mod) = cm
out.write(' \n')
if sep == '' or sep == ',':
wrapper = 'sequence'
elif sep == '|':
wrapper = 'choice'
out.write(' <%s>\n' % wrapper)
for cp in cps:
if len(cp) == 2:
(name, mod) = cp
if name == "#PCDATA":
continue
if mod == '?':
occurs = ' minOccurs="0" maxOccurs="1"'
elif mod == '*':
occurs = ' minOccurs="0" maxOccurs="*"'
elif mod == '+':
occurs = ' minOccurs="1" maxOccurs="*"'
else:
occurs = ''
out.write(' \n' % (name, occurs))
elif len(cp) == 3:
write_cm(out, cp)
else:
out.write(' \n' % (cp,))
out.write(' %s>\n' % wrapper)
out.write(' \n')
# ===== MAIN PROGRAM
# --- Interpreting command-line
if len(sys.argv) < 2 or len(sys.argv) > 3:
print usage
sys.exit(1)
infile = sys.argv[1]
if len(sys.argv) == 3:
outfile = sys.argv[2]
else:
ext = os.path.splitext(infile)[1]
outfile = os.path.split(infile)[1]
outfile = outfile[ : -len(ext)] + ".xsd"
# --- Doing the job
print "\ndtd2schema.py\n"
# Load DTD
print "Loading DTD..."
dtd = xmldtd.load_dtd(infile)
# Find attribute groups
print "Doing reverse-engineering..."
attrinfo = find_attr_groups(dtd)
# Write out schema
print "Writing out schema"
out = open(outfile, "w")
out.write('\n')
out.write('\n\n')
out.write('\n\n')
if attrinfo:
out.write('\n\n')
for group in attrinfo.get_groups():
write_attribute_group(out, group, attrinfo)
out.write("\n")
out.write('\n\n')
for elemname in dtd.get_elements():
elem = dtd.get_elem(elemname)
out.write(' \n' % elemname)
write_element_type(out, elem, attrinfo)
out.write(' \n\n')
notations = dtd.get_notations()
if notations != []:
out.write('\n\n\n\n')
for notname in notations:
(pubid, sysid) = dtd.get_notation(notname)
if sysid == None:
sysid = ''
else:
sysid = ' system="%s"'
out.write(' \n' %
(notname, pubid, sysid))
out.write('\n')
out.close()
PyXML-0.8.2/demo/xmlproc/dtdcheck.py 0100644 0000764 0000144 00000003042 07413602741 016446 0 ustar martin users from xml.parsers.xmlproc import xmlproc
import sys
class DTDReporter(xmlproc.DTDConsumer):
"A simple class that just prints out the events it receives."
def __init__(self,parser,out=sys.stdout):
xmlproc.DTDConsumer.__init__(self,parser)
self.out=out
def new_general_entity(self,name,val):
self.out.write("ENTITY: %s [%s]\n" % (name,val))
def new_external_entity(self,ent_name,pub_id,sys_id,ndata):
self.out.write("EXTERNAL ENTITY: %s P: [%s] S: [%s] N: %s\n" %\
(ent_name,pub_id,sys_id,ndata))
def new_parameter_entity(self,name,val):
self.out.write("PE: %s [%s]\n" % (name,val))
def new_external_pe(self,name,pubid,sysid):
self.out.write("EXTERNAL PE: %s P: [%s] S: [%s]\n" % (name,pubid,sysid))
def new_notation(self,name,pubid,sysid):
self.out.write("NOTATION: %s P: [%s] S: [%s]\n" % (name,pubid,sysid))
def new_attribute(self,elem,attr,a_type,a_decl,a_def):
self.out.write("ATTLIST: %s %s %s %s [%s]\n" % (elem,attr,a_type,a_decl,a_def))
def new_element_type(self,elem_name,elem_cont):
self.out.write("ELEMENT: %s %s\n" % (elem_name,`elem_cont`))
# --- Client methods
def close(self):
self.out.close()
# --- Main program
if __name__ == '__main__':
t=xmlproc.DTDParser()
t.set_dtd_consumer(DTDReporter(t))
t.parse_resource(sys.argv[1])
#t.parse_resource("c:\\minedo~1\\data\\sgml\\xml\\xbel-1.0.dtd")
#t.parse_resource("c:\\minedo~1\\programmering\\python\\xml\\stddirs\\petest.dtd")
PyXML-0.8.2/demo/xmlproc/dtdcmd.py 0100644 0000764 0000144 00000003314 07413602741 016136 0 ustar martin users #!/usr/bin/python
"""
A simple command-line interface to the DTD parser. Intended for those rare
cases when one wants to just parse a DTD and nothing more.
"""
import sys, getopt
from xml.parsers.xmlproc import xmlproc,dtdparser,utils,xmldtd
# --- Doco
usage=\
"""
Usage:
python dtdcmd.py [--list] +
---Options:
--list: List all declarations after parsing.
"""
# --- Utilities
def paired_list_to_hash(list):
hash = {}
for (name, value) in list:
hash[name] = value
return hash
# --- Functionality
def listdecls(dtd):
print
print "=== DECLARATIONS"
print
print "---Elements"
elems = dtd.get_elements()
elems.sort()
for elem in elems:
print elem
print
print "---Entities"
ents = dtd.get_general_entities()
ents.sort()
for ent in ents:
print ent
print
print "---Notations"
nots = dtd.get_notations()
if nots == []:
print "No notations declared."
else:
nots.sort()
for notation in nots:
print notation
# --- Head
print
print "xmlproc version %s" % xmlproc.version
# --- Argument interpretation
try:
(options,sysids)=getopt.getopt(sys.argv[1:],"",["list"])
except getopt.error,e:
print "Usage error: "+e
print usage
sys.exit(1)
options = paired_list_to_hash(options)
list = options.has_key("--list")
# --- Initialization
parser=dtdparser.DTDParser()
if list:
dtd = xmldtd.CompleteDTD(parser)
parser.set_dtd_consumer(dtd)
parser.set_error_handler(utils.ErrorPrinter(parser))
# --- Parsing
for sysid in sysids:
print "Parsing",sysid
parser.parse_resource(sysid)
print "Parsing complete"
# --- Reporting
if list:
listdecls(dtd)
PyXML-0.8.2/demo/xmlproc/dtddoc.py 0100644 0000764 0000144 00000005611 07413602741 016142 0 ustar martin users from xml.parsers.xmlproc import dtdparser,xmlapp,xmldtd,utils
import sys
# --- Utility functions
def print_cm(out,cm):
if cm==None:
out.write("ANY")
return
elif cm[1]==[]:
out.write("EMPTY")
return
(sep,cont,mod)=cm
out.write("(")
for item in cont[:-1]:
if len(item)==2:
out.write('%s%s %s ' % (item[0],item[0],item[1],
sep))
else:
print_cm(out,item)
out.write(sep+" ")
item=cont[-1]
if len(item)==2:
out.write('%s%s' % (item[0],item[0],item[1]))
else:
print_cm(out,item)
out.write(sep+" ")
out.write(")%s " % mod)
# --- Main program
if len(sys.argv) != 2:
print "Usage: dtddoc.py [file name of DTD file]"
sys.exit(1)
# Parsing the DTD
print "Parsing DTD"
dp=dtdparser.DTDParser()
dp.set_error_handler(utils.ErrorPrinter(dp))
dtd=xmldtd.CompleteDTD(dp)
#dtd.compile_content_models(0)
dp.set_dtd_consumer(dtd)
dp.parse_resource(sys.argv[1])
# Processing the DTD
print "Processing DTD"
parents={}
def traverse_cm(cur,cm):
if cm==None:
return
for item in cm[1]:
if len(item)==2:
try:
parents[item[0]][cur]=1
except KeyError:
print "ERROR: Undeclared element '%s'" % item[0]
else:
traverse_cm(cur,item)
parents["#PCDATA"]={}
for elem_name in dtd.get_elements():
parents[elem_name]={}
for elem_name in dtd.get_elements():
elem=dtd.get_elem(elem_name)
traverse_cm(elem_name,elem.get_content_model())
# Printing documentation
print "Printing documentation"
out=open("out.html","w")
out.write(
"""
DTD Documentation
DTD Documentation
""")
elems=dtd.get_elements()
elems.sort()
for elem_name in elems:
out.write('