* support for multiple xml implementations

* inform other modules that autoxml has been factored out
This commit is contained in:
Eray Özkural
2005-11-09 17:40:54 +00:00
parent ba1c4c3b19
commit c4fe20dc32
11 changed files with 590 additions and 93 deletions
+2 -1
View File
@@ -41,7 +41,8 @@ _ = __trans.ugettext
# PiSi # PiSi
import pisi import pisi
# TODO: find the appropriate xmlext implementation and import from there # TODO: find the appropriate xmlext implementation and import from there
from pisi.xmlextmdom import * from pisi.xmlext import *
from pisi.xmlfile import XmlFile
import pisi.context as ctx import pisi.context as ctx
import pisi.util as util import pisi.util as util
import pisi.oo as oo import pisi.oo as oo
+7 -7
View File
@@ -21,18 +21,18 @@ _ = __trans.ugettext
import pisi.context as ctx import pisi.context as ctx
import pisi.packagedb as packagedb import pisi.packagedb as packagedb
from pisi.version import Version from pisi.version import Version
import pisi.xmlfile as xmlfile import pisi.autoxml as autoxml
from pisi.util import Checks from pisi.util import Checks
class Dependency: class Dependency:
__metaclass__ = xmlfile.autoxml __metaclass__ = autoxml.autoxml
s_Package = [xmlfile.String, xmlfile.mandatory] s_Package = [autoxml.String, autoxml.mandatory]
a_versionFrom = [xmlfile.String, xmlfile.optional] a_versionFrom = [autoxml.String, autoxml.optional]
a_versionTo = [xmlfile.String, xmlfile.optional] a_versionTo = [autoxml.String, autoxml.optional]
a_releaseFrom = [xmlfile.String, xmlfile.optional] a_releaseFrom = [autoxml.String, autoxml.optional]
a_releaseTo = [xmlfile.String, xmlfile.optional] a_releaseTo = [autoxml.String, autoxml.optional]
def __str__(self): def __str__(self):
s = self.package s = self.package
+9 -9
View File
@@ -15,32 +15,32 @@
# Authors: Eray Ozkural <eray@uludag.org.tr> # Authors: Eray Ozkural <eray@uludag.org.tr>
import pisi.xmlfile as xmlfile import pisi.autoxml as autoxml
from pisi.util import Checks from pisi.util import Checks
import pisi.lockeddbshelve as shelve import pisi.lockeddbshelve as shelve
class File: class File:
"""File holds the information for a File node/tag in files.xml""" """File holds the information for a File node/tag in files.xml"""
__metaclass__ = xmlfile.autoxml __metaclass__ = autoxml.autoxml
t_Path = [ xmlfile.String, xmlfile.mandatory ] t_Path = [ autoxml.String, autoxml.mandatory ]
t_Type = [ xmlfile.String, xmlfile.mandatory ] t_Type = [ autoxml.String, autoxml.mandatory ]
t_Size = [ xmlfile.Long, xmlfile.optional ] t_Size = [ autoxml.Long, autoxml.optional ]
t_Hash = [ xmlfile.String, xmlfile.optional, "SHA1Sum" ] t_Hash = [ autoxml.String, autoxml.optional, "SHA1Sum" ]
def __str__(self): def __str__(self):
s = "%s, type: %s, size: %s, sha1sum: %s" % (self.path, self.type, s = "%s, type: %s, size: %s, sha1sum: %s" % (self.path, self.type,
self.size, self.hash) self.size, self.hash)
return s return s
class Files(xmlfile.XmlFile): class Files(autoxml.XmlFile):
__metaclass__ = xmlfile.autoxml __metaclass__ = autoxml.autoxml
tag = "Files" tag = "Files"
t_List = [ [File], xmlfile.optional, "File"] t_List = [ [File], autoxml.optional, "File"]
def append(self, fileinfo): def append(self, fileinfo):
self.list.append(fileinfo) self.list.append(fileinfo)
+4 -4
View File
@@ -29,19 +29,19 @@ import pisi.packagedb as packagedb
import pisi.util as util import pisi.util as util
from pisi.package import Package from pisi.package import Package
from pisi.xmlfile import XmlFile from pisi.xmlfile import XmlFile
import pisi.xmlfile as xmlfile import pisi.autoxml as autoxml
from pisi.uri import URI from pisi.uri import URI
class Error(pisi.Error): class Error(pisi.Error):
pass pass
class Index(XmlFile): class Index(XmlFile):
__metaclass__ = xmlfile.autoxml __metaclass__ = autoxml.autoxml
tag = "PISI" tag = "PISI"
t_Sources = [ [specfile.Source], xmlfile.optional, "Source"] t_Sources = [ [specfile.Source], autoxml.optional, "Source"]
t_Packages = [ [metadata.Package], xmlfile.optional, "Package"] t_Packages = [ [metadata.Package], autoxml.optional, "Package"]
def read_uri(self, filename, repo = None): def read_uri(self, filename, repo = None):
"""Read PSPEC file""" """Read PSPEC file"""
+17 -16
View File
@@ -26,24 +26,25 @@ _ = __trans.ugettext
import pisi.context as ctx import pisi.context as ctx
import pisi.specfile as specfile import pisi.specfile as specfile
import pisi.xmlfile as xmlfile import pisi.xmlfile as xmlfile
import pisi.autoxml as autoxml
import pisi.util as util import pisi.util as util
class Source: class Source:
__metaclass__ = xmlfile.autoxml __metaclass__ = autoxml.autoxml
t_Name = [xmlfile.String, xmlfile.mandatory] t_Name = [autoxml.String, autoxml.mandatory]
t_Homepage = [xmlfile.String, xmlfile.optional] t_Homepage = [autoxml.String, autoxml.optional]
t_Packager = [specfile.Packager, xmlfile.mandatory] t_Packager = [specfile.Packager, autoxml.mandatory]
class Package(specfile.Package): class Package(specfile.Package):
__metaclass__ = xmlfile.autoxml __metaclass__ = autoxml.autoxml
t_Build = [ xmlfile.Integer, xmlfile.optional] t_Build = [ autoxml.Integer, autoxml.optional]
t_Distribution = [ xmlfile.String, xmlfile.mandatory] t_Distribution = [ autoxml.String, autoxml.mandatory]
t_DistributionRelease = [ xmlfile.String, xmlfile.mandatory] t_DistributionRelease = [ autoxml.String, autoxml.mandatory]
t_Architecture = [ xmlfile.String, xmlfile.mandatory] t_Architecture = [ autoxml.String, autoxml.mandatory]
t_InstalledSize = [ xmlfile.Long, xmlfile.mandatory] t_InstalledSize = [ autoxml.Long, autoxml.mandatory]
t_PackageURI = [ xmlfile.String, xmlfile.optional] t_PackageURI = [ autoxml.String, autoxml.optional]
def decode_hook(self, node, errs, where): def decode_hook(self, node, errs, where):
self.version = self.history[0].version self.version = self.history[0].version
@@ -57,17 +58,17 @@ class Package(specfile.Package):
(self.architecture, self.installedSize) (self.architecture, self.installedSize)
return s return s
class MetaData(xmlfile.XmlFile): class MetaData(autoxml.XmlFile):
"""Package metadata. Metadata is composed of Specfile and various """Package metadata. Metadata is composed of Specfile and various
other information. A metadata has two parts, Source and Package.""" other information. A metadata has two parts, Source and Package."""
__metaclass__ = xmlfile.autoxml __metaclass__ = autoxml.autoxml
tag = "PISI" tag = "PISI"
t_Source = [ Source, xmlfile.mandatory] t_Source = [ Source, autoxml.mandatory]
t_Package = [ Package, xmlfile.mandatory] t_Package = [ Package, autoxml.mandatory]
#t_History = [ [Update], xmlfile.mandatory] #t_History = [ [Update], autoxml.mandatory]
def from_spec(self, src, pkg): def from_spec(self, src, pkg):
self.source.name = src.name self.source.name = src.name
+55 -55
View File
@@ -26,8 +26,8 @@ _ = __trans.ugettext
from os.path import basename from os.path import basename
# pisi modules # pisi modules
import pisi.xmlfile as xmlfile
from pisi.xmlfile import XmlFile from pisi.xmlfile import XmlFile
import pisi.autoxml as autoxml
import pisi.context as ctx import pisi.context as ctx
from pisi.dependency import Dependency from pisi.dependency import Dependency
import pisi.dependency import pisi.dependency
@@ -37,12 +37,12 @@ import pisi.util as util
class Error(pisi.Error): class Error(pisi.Error):
pass pass
__metaclass__ = xmlfile.autoxml __metaclass__ = autoxml.autoxml
class Packager: class Packager:
t_Name = [xmlfile.Text, xmlfile.mandatory] t_Name = [autoxml.Text, autoxml.mandatory]
t_Email = [xmlfile.String, xmlfile.mandatory] t_Email = [autoxml.String, autoxml.mandatory]
def __str__(self): def __str__(self):
s = "%s <%s>" % (self.name, self.email) s = "%s <%s>" % (self.name, self.email)
@@ -51,9 +51,9 @@ class Packager:
class AdditionalFile: class AdditionalFile:
s_Filename = [xmlfile.String, xmlfile.mandatory] s_Filename = [autoxml.String, autoxml.mandatory]
a_target = [xmlfile.String, xmlfile.mandatory] a_target = [autoxml.String, autoxml.mandatory]
a_permission = [xmlfile.String, xmlfile.optional] a_permission = [autoxml.String, autoxml.optional]
def __str__(self): def __str__(self):
s = "%s -> %s " % (self.filename, self.target) s = "%s -> %s " % (self.filename, self.target)
@@ -64,10 +64,10 @@ class AdditionalFile:
class Patch: class Patch:
s_Filename = [xmlfile.String, xmlfile.mandatory] s_Filename = [autoxml.String, autoxml.mandatory]
a_compressionType = [xmlfile.String, xmlfile.optional] a_compressionType = [autoxml.String, autoxml.optional]
a_level = [xmlfile.Integer, xmlfile.optional] a_level = [autoxml.Integer, autoxml.optional]
a_target = [xmlfile.String, xmlfile.optional] a_target = [autoxml.String, autoxml.optional]
#FIXME: what's the cleanest way to give a default value for reading level? #FIXME: what's the cleanest way to give a default value for reading level?
#def decode_hook(self, node, errs, where): #def decode_hook(self, node, errs, where):
@@ -87,10 +87,10 @@ class Patch:
class Update: class Update:
a_release = [xmlfile.String, xmlfile.mandatory] a_release = [autoxml.String, autoxml.mandatory]
t_Date = [xmlfile.String, xmlfile.mandatory] t_Date = [autoxml.String, autoxml.mandatory]
t_Version = [xmlfile.String, xmlfile.mandatory] t_Version = [autoxml.String, autoxml.mandatory]
t_Type = [xmlfile.String, xmlfile.optional] t_Type = [autoxml.String, autoxml.optional]
def __str__(self): def __str__(self):
s = self.date s = self.date
@@ -103,8 +103,8 @@ class Update:
class Path: class Path:
s_Path = [xmlfile.String, xmlfile.mandatory] s_Path = [autoxml.String, autoxml.mandatory]
a_fileType = [xmlfile.String, xmlfile.optional] a_fileType = [autoxml.String, autoxml.optional]
def __str__(self): def __str__(self):
s = self.path s = self.path
@@ -114,8 +114,8 @@ class Path:
class ComarProvide: class ComarProvide:
s_om = [xmlfile.String, xmlfile.mandatory] s_om = [autoxml.String, autoxml.mandatory]
a_script = [xmlfile.String, xmlfile.mandatory] a_script = [autoxml.String, autoxml.mandatory]
def __str__(self): def __str__(self):
# FIXME: descriptive enough? # FIXME: descriptive enough?
@@ -126,9 +126,9 @@ class ComarProvide:
class Archive: class Archive:
s_uri = [ xmlfile.String, xmlfile.mandatory ] s_uri = [ autoxml.String, autoxml.mandatory ]
a_type =[ xmlfile.String, xmlfile.mandatory ] a_type =[ autoxml.String, autoxml.mandatory ]
a_sha1sum =[ xmlfile.String, xmlfile.mandatory ] a_sha1sum =[ autoxml.String, autoxml.mandatory ]
def decode_hook(self, node, errs, where): def decode_hook(self, node, errs, where):
self.name = basename(self.uri) self.name = basename(self.uri)
@@ -140,38 +140,38 @@ class Archive:
class Source: class Source:
t_Name = [xmlfile.String, xmlfile.mandatory] t_Name = [autoxml.String, autoxml.mandatory]
t_Homepage = [xmlfile.String, xmlfile.optional] t_Homepage = [autoxml.String, autoxml.optional]
t_Packager = [Packager, xmlfile.mandatory] t_Packager = [Packager, autoxml.mandatory]
t_Summary = [xmlfile.LocalText, xmlfile.mandatory] t_Summary = [autoxml.LocalText, autoxml.mandatory]
t_Description = [xmlfile.LocalText, xmlfile.mandatory] t_Description = [autoxml.LocalText, autoxml.mandatory]
t_IsA = [ [xmlfile.String], xmlfile.mandatory] t_IsA = [ [autoxml.String], autoxml.mandatory]
t_PartOf = [xmlfile.String, xmlfile.mandatory] t_PartOf = [autoxml.String, autoxml.mandatory]
t_Icon = [ xmlfile.String, xmlfile.optional] t_Icon = [ autoxml.String, autoxml.optional]
t_License = [ [xmlfile.String], xmlfile.mandatory] t_License = [ [autoxml.String], autoxml.mandatory]
t_Archive = [Archive, xmlfile.mandatory ] t_Archive = [Archive, autoxml.mandatory ]
t_Patches = [ [Patch], xmlfile.optional] t_Patches = [ [Patch], autoxml.optional]
t_BuildDependencies = [ [Dependency], xmlfile.optional] t_BuildDependencies = [ [Dependency], autoxml.optional]
t_Version = [ xmlfile.String, xmlfile.optional] t_Version = [ autoxml.String, autoxml.optional]
t_Release = [ xmlfile.String, xmlfile.optional] t_Release = [ autoxml.String, autoxml.optional]
class Package: class Package:
t_Name = [ xmlfile.String, xmlfile.mandatory ] t_Name = [ autoxml.String, autoxml.mandatory ]
t_Summary = [ xmlfile.LocalText, xmlfile.optional ] t_Summary = [ autoxml.LocalText, autoxml.optional ]
t_Description = [ xmlfile.LocalText, xmlfile.optional ] t_Description = [ autoxml.LocalText, autoxml.optional ]
t_IsA = [ [xmlfile.String], xmlfile.optional] t_IsA = [ [autoxml.String], autoxml.optional]
t_PartOf = [xmlfile.String, xmlfile.optional] t_PartOf = [autoxml.String, autoxml.optional]
t_License = [ [xmlfile.String], xmlfile.optional] t_License = [ [autoxml.String], autoxml.optional]
t_Icon = [ xmlfile.String, xmlfile.optional] t_Icon = [ autoxml.String, autoxml.optional]
t_RuntimeDependencies = [ [Dependency], xmlfile.optional] t_RuntimeDependencies = [ [Dependency], autoxml.optional]
t_Files = [ [Path], xmlfile.optional] t_Files = [ [Path], autoxml.optional]
t_Conflicts = [ [xmlfile.String], xmlfile.optional, "Conflicts/Package"] t_Conflicts = [ [autoxml.String], autoxml.optional, "Conflicts/Package"]
t_ProvidesComar = [ [ComarProvide], xmlfile.optional, "Provides/COMAR"] t_ProvidesComar = [ [ComarProvide], autoxml.optional, "Provides/COMAR"]
#t_RequiresComar = [ [xmlfile.String], xmlfile.mandatory, "Requires/COMAR"] #t_RequiresComar = [ [autoxml.String], autoxml.mandatory, "Requires/COMAR"]
t_AdditionalFiles = [ [AdditionalFile], xmlfile.optional] t_AdditionalFiles = [ [AdditionalFile], autoxml.optional]
t_History = [ [Update], xmlfile.optional] t_History = [ [Update], autoxml.optional]
def pkg_dir(self): def pkg_dir(self):
packageDir = self.name + '-' \ packageDir = self.name + '-' \
@@ -198,18 +198,18 @@ class Package:
class SpecFile(XmlFile): class SpecFile(XmlFile):
__metaclass__ = xmlfile.autoxml #needed when we specify a superclass __metaclass__ = autoxml.autoxml #needed when we specify a superclass
tag = "PISI" tag = "PISI"
t_Source = [ Source, xmlfile.mandatory] t_Source = [ Source, autoxml.mandatory]
t_Packages = [ [Package], xmlfile.mandatory, "Package"] t_Packages = [ [Package], autoxml.mandatory, "Package"]
t_History = [ [Update], xmlfile.mandatory] t_History = [ [Update], autoxml.mandatory]
#we're not doing this with the init hook right now #we're not doing this with the init hook right now
#def init(self, tag = "PISI"): #def init(self, tag = "PISI"):
#ignore tag #ignore tag
#XmlFile.__init__(self, tag) #autoxml.__init__(self, tag)
def read_hook(self, errs): def read_hook(self, errs):
"""Read PSPEC file""" """Read PSPEC file"""
+14
View File
@@ -0,0 +1,14 @@
# -*- 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>
from xmlextmdom import *
+8 -1
View File
@@ -14,9 +14,16 @@
# Gurer Ozen <gurer@uludag.org.tr> # Gurer Ozen <gurer@uludag.org.tr>
""" """
some helper functions implemented with minidom xmlext is a helper module for accessing XML files using
xml.dom.minidom.
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, function names are mixedCase for compatibility with minidom,
an 'old library' an 'old library'
note: this is a particularly inefficient implementation of xmlext. note: this is a particularly inefficient implementation of xmlext.
""" """
+170
View File
@@ -0,0 +1,170 @@
# -*- 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>
"""
some helper functions for high-level access to XML structures
this implementation uses piksemel, a fast C-based XML library
function names are mixedCase for compatibility with minidom,
an old library
"""
import gettext
__trans = gettext.translation('pisi', fallback=True)
_ = __trans.ugettext
import pisi
import piksemel as iks
class XmlError(pisi.Error):
"named this way because the class if mostly used with an import *"
pass
def getNodeAttribute(node, attrname):
"""get named attribute from DOM node"""
if not node.hasAttribute(attrname):
return None
return node.getAttribute(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:
for child in node.childNodes:
if child.nodeType == node.ELEMENT_NODE and child.tagName == tag:
return child
return None
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.createElement(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 newNode(node, tag):
return node.ownerDocument.createElement(tag)
def newTextNode(node, text):
return node.ownerDocument.createTextNode(text)
def addText(node, tagPath, text, branch = True):
newnode = newTextNode(node, text)
addNode(node, tagPath, newnode, branch)
+154
View File
@@ -0,0 +1,154 @@
# -*- 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>
"""
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'
note: this is a particularly inefficient implementation of xmlfile
"""
import gettext
__trans = gettext.translation('pisi', fallback=True)
_ = __trans.ugettext
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.newDOM()
def newDOM(self):
"""clear DOM"""
impl = mdom.getDOMImplementation()
self.dom = impl.createDocument(None, self.rootTag, None)
def unlink(self):
"""deallocate DOM structure"""
self.dom.unlink()
def rootNode(self):
"""returns root document element"""
return self.dom.documentElement
def readxml(self, fileName):
try:
self.dom = mdom.parse(fileName)
except ExpatError, inst:
raise XmlError(_("File '%s' has invalid XML: %s\n") % (fileName,
str(inst)))
def writexml(self, fileName):
f = codecs.open(fileName,'w', "utf-8")
f.write(self.dom.toprettyxml())
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.createElement(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))
+150
View File
@@ -0,0 +1,150 @@
# -*- 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>
# Gurer Ozen <gurer@uludag.org.tr>
# Baris Metin <baris@uludag.org.tr
"""
XmlFile class further abstracts a dom object using the
high-level dom functions provided in xmlext module
this implementation uses piksemel, a fast C-based XML library
"""
import gettext
__trans = gettext.translation('pisi', fallback=True)
_ = __trans.ugettext
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.newDOM()
def newDOM(self):
"""clear DOM"""
impl = mdom.getDOMImplementation()
self.dom = impl.createDocument(None, self.rootTag, None)
def unlink(self):
"""deallocate DOM structure"""
self.dom.unlink()
def rootNode(self):
"""returns root document element"""
return self.dom.documentElement
def readxml(self, fileName):
try:
self.dom = mdom.parse(fileName)
except ExpatError, inst:
raise XmlError(_("File '%s' has invalid XML: %s\n") % (fileName,
str(inst)))
def writexml(self, fileName):
f = codecs.open(fileName,'w', "utf-8")
f.write(self.dom.toprettyxml())
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.createElement(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))