* implement 4suite domlette support based on faik's patch
* but it cannot encode xml:lang attributes, needs a fix :(
This commit is contained in:
+5
-5
@@ -101,7 +101,7 @@ class LocalText(dict):
|
||||
assert self.tag != ''
|
||||
for key in self.iterkeys():
|
||||
newnode = newNode(node, self.tag)
|
||||
newnode.setAttribute('xml:lang', key)
|
||||
newnode.setAttributeNS(None, 'xml:lang', key)
|
||||
newtext = newTextNode(node, self[key])
|
||||
newnode.appendChild(newtext)
|
||||
node.appendChild(newnode)
|
||||
@@ -400,7 +400,7 @@ class autoxml(oo.autosuper, oo.autoprop):
|
||||
errs.append(_("autoxml.write: object validation has failed"))
|
||||
raise Error(*errs)
|
||||
errs = []
|
||||
self.newDOM()
|
||||
self.newDocument()
|
||||
self.encode(self.rootNode(), errs)
|
||||
if hasattr(self, 'write_hook'):
|
||||
self.write_hook(errs)
|
||||
@@ -423,7 +423,7 @@ class autoxml(oo.autosuper, oo.autoprop):
|
||||
return getNodeAttribute(node, attr)
|
||||
def writetext(node, attr, text):
|
||||
#print 'write attr', attr, text
|
||||
node.setAttribute(attr, text)
|
||||
node.setAttributeNS(None, attr, text)
|
||||
anonfuns = cls.gen_anon_basic(attr, spec, readtext, writetext)
|
||||
return cls.gen_named_comp(attr, spec, anonfuns)
|
||||
|
||||
@@ -637,7 +637,7 @@ class autoxml(oo.autosuper, oo.autoprop):
|
||||
if node and obj:
|
||||
try:
|
||||
#FIXME: this doesn't look pretty
|
||||
classnode = node.ownerDocument.createElement(tag)
|
||||
classnode = newNode(node, tag)
|
||||
obj.encode(classnode, errs)
|
||||
node.appendChild(classnode)
|
||||
except Error:
|
||||
@@ -684,7 +684,7 @@ class autoxml(oo.autosuper, oo.autoprop):
|
||||
errs.append(where + _('Mandatory list empty'))
|
||||
ix = 1
|
||||
for node in nodes:
|
||||
dummy = node.ownerDocument.createElement("Dummy")
|
||||
dummy = newNode(node, "Dummy")
|
||||
dummy.appendChild(node)
|
||||
l.append(decode_item(dummy, errs, where + unicode("[%s]" % ix)))
|
||||
#l.append(decode_item(node, errs, where + unicode("[%s]" % ix)))
|
||||
|
||||
+5
-2
@@ -15,5 +15,8 @@ try:
|
||||
zimbabwe # comment out to disable piks
|
||||
from xmlextpiks import *
|
||||
except:
|
||||
print 'xmlext: piksemel implementation cannot be loaded, falling back to minidom'
|
||||
from xmlextmdom import *
|
||||
try:
|
||||
from xmlextcdom import *
|
||||
except:
|
||||
print 'xmlext: cDomlette/piksemel implementation cannot be loaded, falling back to minidom'
|
||||
from xmlextmdom import *
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2005, TUBITAK/UEKAE
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# Please read the COPYING file.
|
||||
#
|
||||
# Authors: Eray Ozkural <eray@uludag.org.tr>
|
||||
# Baris Metin <baris@uludag.org.tr
|
||||
# Gurer Ozen <gurer@uludag.org.tr>
|
||||
# Faik Uygur <faikuygur@gmail.com>
|
||||
|
||||
"""
|
||||
xmlext is a helper module for accessing XML files using
|
||||
xml.dom.minidom . It is a convenient wrapper for some
|
||||
DOM functions, and provides path based get/add functions
|
||||
as in KDE API.
|
||||
|
||||
function names are mixedCase for compatibility with minidom,
|
||||
an 'old library'
|
||||
|
||||
this implementation uses cDomlette from 4suite.org
|
||||
adapted from the minidom implementation by Faik Uygur.
|
||||
"""
|
||||
|
||||
import gettext
|
||||
__trans = gettext.translation('pisi', fallback=True)
|
||||
_ = __trans.ugettext
|
||||
|
||||
import Ft
|
||||
from Ft.Xml.Domlette import implementation
|
||||
from Ft.Xml import ParsePath
|
||||
from Ft.Xml.Domlette import NonvalidatingReader
|
||||
|
||||
import pisi
|
||||
|
||||
class XmlError(pisi.Error):
|
||||
"named this way because the class if mostly used with an import *"
|
||||
pass
|
||||
|
||||
# Document wrappers
|
||||
|
||||
def newDocument(tag):
|
||||
# create a document and return document root
|
||||
doc = implementation.createDocument(None, tag, None)
|
||||
return doc.documentElement
|
||||
|
||||
def parse(filename):
|
||||
# parse file and return document root
|
||||
try:
|
||||
doc = ParsePath(filename)
|
||||
return doc.documentElement
|
||||
except Ft.FtException, e:
|
||||
raise Error(_("File '%s' has invalid XML: %s") % (filename, str(e)))
|
||||
|
||||
def newNode(node, tag):
|
||||
return node.ownerDocument.createElementNS(None, tag)
|
||||
|
||||
def newTextNode(node, text):
|
||||
return node.ownerDocument.createTextNode(text)
|
||||
|
||||
# Node related wrappers
|
||||
|
||||
def getNodeAttribute(node, attrname):
|
||||
"""get named attribute from DOM node"""
|
||||
if not node.hasAttributeNS(None, attrname):
|
||||
return None
|
||||
else:
|
||||
return node.getAttributeNS(None, attrname)
|
||||
|
||||
def getChildElts(node):
|
||||
"""get only child elements"""
|
||||
return filter(lambda x:x.nodeType == x.ELEMENT_NODE, node.childNodes)
|
||||
|
||||
def getTagByName(parent, childName):
|
||||
return [x for x in parent.childNodes
|
||||
if x.nodeType == x.ELEMENT_NODE and x.tagName == childName]
|
||||
|
||||
def getNodeText(node, tagpath = ""):
|
||||
"""get the first child and expect it to be text!"""
|
||||
if tagpath!="":
|
||||
node = getNode(node, tagpath)
|
||||
try:
|
||||
child = node.childNodes[0]
|
||||
except IndexError:
|
||||
return None
|
||||
except AttributeError: # no node by that name
|
||||
return None
|
||||
if child.nodeType == child.TEXT_NODE:
|
||||
# in any case, strip whitespaces...
|
||||
return child.data.strip()
|
||||
else:
|
||||
raise XmlError(_("getNodeText: Expected text node, got something else!"))
|
||||
|
||||
def getChildText(node_s, tagpath):
|
||||
"""get the text of a child at the end of a tag path"""
|
||||
node = getNode(node_s, tagpath)
|
||||
if not node:
|
||||
return None
|
||||
return getNodeText(node)
|
||||
|
||||
def getNode(node, tagpath):
|
||||
"""returns the *first* matching node for given tag path."""
|
||||
|
||||
assert type(tagpath)==str
|
||||
tags = tagpath.split('/')
|
||||
assert len(tags)>0
|
||||
|
||||
# iterative code to search for the path
|
||||
for tag in tags:
|
||||
currentNode = None
|
||||
for child in node.childNodes:
|
||||
if child.nodeType == node.ELEMENT_NODE and child.tagName == tag:
|
||||
currentNode = child
|
||||
break
|
||||
if not currentNode:
|
||||
return None
|
||||
else:
|
||||
node = currentNode
|
||||
return currentNode
|
||||
|
||||
def getAllNodes(node, tagPath):
|
||||
"""retrieve all nodes that match a given tag path."""
|
||||
|
||||
#FIXME: better tag split
|
||||
tags = tagPath.split('/')
|
||||
|
||||
if len(tags) == 0:
|
||||
return []
|
||||
|
||||
nodeList = [node] # basis case
|
||||
|
||||
for tag in tags:
|
||||
results = map(lambda x: getTagByName(x, tag), nodeList)
|
||||
nodeList = []
|
||||
for x in results:
|
||||
nodeList.extend(x)
|
||||
pass # emacs indentation error, keep it here
|
||||
|
||||
if len(nodeList) == 0:
|
||||
return []
|
||||
|
||||
return nodeList
|
||||
|
||||
def createTagPath(node, tags):
|
||||
"""create new child at the end of a tag chain starting from node
|
||||
no matter what"""
|
||||
if len(tags)==0:
|
||||
return node
|
||||
dom = node.ownerDocument
|
||||
for tag in tags:
|
||||
node = node.appendChild(dom.createElementNS(None, tag))
|
||||
return node
|
||||
|
||||
def addTagPath(node, tags, newnode=None):
|
||||
"""add newnode at the end of a tag chain, smart one"""
|
||||
node = createTagPath(node, tags)
|
||||
if newnode: # node to add specified
|
||||
node.appendChild(newnode)
|
||||
return node
|
||||
|
||||
def addNode(node, tagpath, newnode = None, branch=True):
|
||||
"""add a new node at the end of the tree and returns it
|
||||
if newnode is given adds that node, too."""
|
||||
|
||||
assert type(tagpath)==str
|
||||
tags = []
|
||||
if tagpath != "":
|
||||
tags = tagpath.split('/') # tag chain
|
||||
else:
|
||||
addTagPath(node, [], newnode)
|
||||
return node #FIXME: is this correct!?!?
|
||||
|
||||
assert len(tags)>0 # we want a chain
|
||||
|
||||
# iterative code to search for the path
|
||||
|
||||
if branch:
|
||||
rem = 1
|
||||
else:
|
||||
rem = 0
|
||||
|
||||
while len(tags) > rem:
|
||||
tag = tags.pop(0)
|
||||
nodeList = getTagByName(node, tag)
|
||||
if len(nodeList) == 0: # couldn't find
|
||||
tags.insert(0, tag) # put it back in
|
||||
return addTagPath(node, tags, newnode)
|
||||
else:
|
||||
node = nodeList[len(nodeList)-1] # discard other matches
|
||||
else:
|
||||
# had only one tag..
|
||||
return addTagPath(node, tags, newnode)
|
||||
|
||||
return node
|
||||
|
||||
def addText(node, tagPath, text, branch = True):
|
||||
newnode = newTextNode(node, text)
|
||||
return addNode(node, tagPath, newnode, branch = branch)
|
||||
+6
-4
@@ -13,8 +13,10 @@
|
||||
|
||||
try:
|
||||
horagata # comment out to disable piks
|
||||
from xmlextpiks import *
|
||||
from xmlfilepiks import *
|
||||
#from xmlfilepiks import *
|
||||
except:
|
||||
print 'xmlfile: piksemel implementation cannot be loaded, falling back to minidom'
|
||||
from xmlfilemdom import *
|
||||
try:
|
||||
from xmlfilecdom import *
|
||||
except:
|
||||
print 'xmlext: cDomlette/piksemel implementation cannot be loaded, falling back to minidom'
|
||||
from xmlfilemdom import *
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2005, TUBITAK/UEKAE
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# Please read the COPYING file.
|
||||
#
|
||||
# Authors: Eray Ozkural <eray@uludag.org.tr>
|
||||
# Baris Metin <baris@uludag.org.tr
|
||||
# Faik Uygur <faikuygur@gmail.com>
|
||||
|
||||
"""
|
||||
XmlFile class further abstracts a dom object using the
|
||||
high-level dom functions provided in xmlext module (and sorely lacking
|
||||
in xml.dom :( )
|
||||
|
||||
function names are mixedCase for compatibility with minidom,
|
||||
an 'old library'
|
||||
|
||||
this implementation uses cDomlette from 4suite.org
|
||||
adapted from the minidom implementation by Faik Uygur.
|
||||
"""
|
||||
|
||||
import gettext
|
||||
__trans = gettext.translation('pisi', fallback=True)
|
||||
_ = __trans.ugettext
|
||||
|
||||
import codecs
|
||||
|
||||
import Ft
|
||||
from Ft.Xml.Domlette import implementation
|
||||
from Ft.Xml.Domlette import NonvalidatingReader
|
||||
from Ft.Xml import Parse, ParsePath
|
||||
from Ft.Xml.Domlette import Print, PrettyPrint
|
||||
|
||||
import pisi
|
||||
|
||||
class Error(pisi.Error):
|
||||
"named this way because the class if mostly used with an import *"
|
||||
pass
|
||||
|
||||
class XmlFile(object):
|
||||
"""A class to help reading and writing an XML file"""
|
||||
|
||||
def __init__(self, tag):
|
||||
self.rootTag = tag
|
||||
self.newDocument()
|
||||
|
||||
def newDocument(self):
|
||||
"""clear DOM"""
|
||||
self.doc = implementation.createDocument(None, self.rootTag, None)
|
||||
|
||||
def unlink(self):
|
||||
"""deallocate DOM structure"""
|
||||
#del self.doc
|
||||
self.doc = None # why?
|
||||
|
||||
def rootNode(self):
|
||||
"""returns root document element"""
|
||||
return self.doc.documentElement
|
||||
|
||||
def readxml(self, path):
|
||||
try:
|
||||
self.doc = ParsePath(path)
|
||||
return self.doc.documentElement
|
||||
except Ft.FtException, e:
|
||||
raise Error(_("File '%s' has invalid XML:") % (path, str(e)) )
|
||||
|
||||
def writexml(self, path):
|
||||
f = file(path, 'w')
|
||||
Print(self.rootNode(), stream = f)
|
||||
f.close()
|
||||
|
||||
def verifyRootTag(self):
|
||||
actual_roottag = self.rootNode().tagName
|
||||
if actual_roottag != self.rootTag:
|
||||
raise Error(_("Root tagname %s not identical to %s as expected") %
|
||||
(actual_roottag, self.rootTag) )
|
||||
|
||||
# construction helpers
|
||||
|
||||
def newNode(self, tag):
|
||||
return self.dom.createElementNS(None, tag)
|
||||
|
||||
def newTextNode(self, text):
|
||||
return self.dom.createTextNode(text)
|
||||
|
||||
def newAttribute(self, attr):
|
||||
return self.dom.createAttribute(attr)
|
||||
|
||||
# read helpers
|
||||
|
||||
def getNode(self, tagPath = ""):
|
||||
"""returns the *first* matching node for given tag path."""
|
||||
self.verifyRootTag()
|
||||
return getNode(self.dom.documentElement, tagPath)
|
||||
|
||||
def getNodeText(self, tagPath):
|
||||
"""returns the text of *first* matching node for given tag path."""
|
||||
node = self.getNode(tagPath)
|
||||
if not node:
|
||||
return None
|
||||
return getNodeText(node)
|
||||
|
||||
def getAllNodes(self, tagPath):
|
||||
"""returns all nodes matching a given tag path."""
|
||||
self.verifyRootTag()
|
||||
return getAllNodes(self.dom.documentElement, tagPath)
|
||||
|
||||
def getChildren(self, tagpath):
|
||||
""" returns the children of the given path"""
|
||||
node = self.getNode(tagpath)
|
||||
return node.childNodes
|
||||
|
||||
# get only elements of a given type
|
||||
#FIXME: this doesn't work
|
||||
def getChildrenWithType(self, tagpath, type):
|
||||
""" returns the children of the given path, only with given type """
|
||||
node = self.getNode(tagpath)
|
||||
return filter(lambda x:x.nodeType == type, node.childNodes)
|
||||
|
||||
# get only child elements
|
||||
def getChildElts(self, tagpath):
|
||||
""" returns the children of the given path, only with given type """
|
||||
node = self.getNode(tagpath)
|
||||
try:
|
||||
return filter(lambda x:x.nodeType == x.ELEMENT_NODE,
|
||||
node.childNodes)
|
||||
except AttributeError:
|
||||
return None
|
||||
|
||||
# write helpers
|
||||
|
||||
def addNode(self, tagPath, newnode = None):
|
||||
"this adds the newnode under given tag path"
|
||||
self.verifyRootTag()
|
||||
return addNode(self.dom.documentElement, tagPath, newnode)
|
||||
|
||||
def addNodeUnder(self, node, tagPath, newnode = None):
|
||||
"this adds the new stuff under node and then following tag path"
|
||||
self.verifyRootTag()
|
||||
return addNode(node, tagPath, newnode)
|
||||
|
||||
def addChild(self, newnode):
|
||||
"add a new child node right under root element document"
|
||||
self.dom.documentElement.appendChild(newnode)
|
||||
|
||||
def addText(self, node, text):
|
||||
"add text to node"
|
||||
node.appendChild(self.newTextNode(text))
|
||||
|
||||
def addTextNode(self, tagPath, text):
|
||||
"add a text node with given tag path"
|
||||
node = self.addNode(tagPath, self.newTextNode(text))
|
||||
return node
|
||||
|
||||
def addTextNodeUnder(self, node, tagPath, text):
|
||||
"add a text node under given node with tag path (phew)"
|
||||
return self.addNodeUnder(node, tagPath, self.newTextNode(text))
|
||||
@@ -43,9 +43,9 @@ class XmlFile(object):
|
||||
|
||||
def __init__(self, tag):
|
||||
self.rootTag = tag
|
||||
self.newDOM()
|
||||
self.newDocument()
|
||||
|
||||
def newDOM(self):
|
||||
def newDocument(self):
|
||||
"""clear DOM"""
|
||||
impl = mdom.getDOMImplementation()
|
||||
self.dom = impl.createDocument(None, self.rootTag, None)
|
||||
|
||||
@@ -36,9 +36,9 @@ class XmlFile(object):
|
||||
|
||||
def __init__(self, tag):
|
||||
self.rootTag = tag
|
||||
self.newDOM()
|
||||
self.newDocument()
|
||||
|
||||
def newDOM(self):
|
||||
def newDocument(self):
|
||||
"""clear DOM"""
|
||||
self.doc = newDocument(self.rootTag)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user