Viewing file: ResourceMetaDataImp.py (33.39 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
######################################################################## # $Header: /var/local/cvsroot/4Suite/Ft/Server/Server/SCore/ResourceMetaDataImp.py,v 1.56 2005/03/28 11:29:12 mbrown Exp $ """ ResourceMetaData repository resource class.
Copyright 2005 Fourthought, Inc. (USA). Detailed license and copyright information: http://4suite.org/COPYRIGHT Project home, documentation, distributions: http://4suite.org/ """
import cStringIO, warnings
from Ft.Rdf import Statement from Ft.Rdf import OBJECT_TYPE_LITERAL, OBJECT_TYPE_RESOURCE from Ft.Server import RESERVED_NAMESPACE, FTSERVER_NAMESPACE from Ft.Server.Common import ResourceTypes, Schema, AclConstants, XmlLib from Ft.Server.Server import FtServerServerException, Error from Ft.Server.Server.Drivers import FtssInputSource import Ft.Server.Server.Xslt from Ft.Xml import XUpdate, InputSource from Ft.Xml.Domlette import Print from Ft.Xml.XLink import XLINK_NAMESPACE from Ft.Xml.XPath import Context, RuntimeException, CompiletimeException import Ft.Xml.Xslt.Processor
class ResourceMetaDataImp: """ Every repository resource inherits from this class in order to store and provide access to information about its existence. """
resourceType = ResourceTypes.ResourceType.META_DATA
def __init__(self, path, driver, cache): """ Construct a new resource metadata object. This is almost always done through _fetchResource().
Params: path is a reference to a PathImp that is the location of this resource in the in the repository. driver is an instance of FtssDriver that represents the connection to the actual on disk repository for use by the resource. cache is a reference to an ObjectCache instance that is a per-transaction cache of objects fetched within this transaction. """ self._path = path self._deleted = 0 self._driver = driver self._cache = cache self._cache.registerResource(self._path, self) self._basePath = self.getBasePath()
############################################### #General interfaces for getting information about the object ############################################### def getPath(self): """ Get the path of this resource, as a Path instance. """ self._verifyTx() return self._path
def getBasePath(self): """ Get the base path of this object, as a Path instance. The only difference between this and getPath is that for all non-container objects it will return the parent's path. For a container object it will return its path. """ self._verifyTx return self._path.getParentPath()
def getDisplayPath(self): """ Get the path relative to the document root, as a string. """ self._verifyTx() return self._path.displayPath
def getAbsolutePath(self): """ Get the full path into the system, as a string. """ self._verifyTx() return self._path.absolutePath
def getAbsolutePathAsUri(self): """ Get the full path into the system, as an absolute URI string. """ self._verifyTx() return self._path.absolutePathAsUri
def getName(self): """ Get the name of the resource, as a string. """ return self._path.name
def getCreationDate(self): """ Get the date that this resource was created. The date will be an ISO 8601 string like u'2002-08-16T22:49:56Z'. """ self._verifyTx() res = self._driver.getSystemModel().complete(self._path.absolutePath, Schema.CREATION_DATE, None) if not res: raise FtServerServerException(Error.UNKNOWN_PATH, path=self._path) return res[0].object
def getLastModifiedDate(self): """ Get the date that this resource was last modified. The date will be an ISO 8601 string like u'2002-08-16T22:49:56Z'. """ self._verifyTx() res = self._driver.getSystemModel().complete(self._path.absolutePath, Schema.MODIFIED_DATE, None) if not res: raise FtServerServerException(Error.UNKNOWN_PATH, path=self._path) return res[0].object
def getSize(self): """ Get the size of the content, in bytes, as an integer. """ self._verifyTx()
res = self._driver.getSystemModel().complete(self._path.absolutePath, Schema.CONTENT_SIZE, None) if not res: raise FtServerServerException(Error.UNKNOWN_PATH, path=self._path) return int(res[0].object)
def getResourceType(self): """ Get the type of this resource. Types are defined in Ft.Server.Common.ResourceTypes.ResourceType. """ self._verifyTx() return self.resourceType
def isResourceType(self, testType): """ Determine if this resource is of a certain type """ self._verifyTx() return ResourceTypes._IsResourceType(self.getResourceType(), testType)
def getContent(self): """ Get the string content of this resource """ self._verifyTx() return self._driver.fetchResource(self._path)
def getContentSlice(self, start=None, end=None): """ Get a piece of our content. Really only makes sense for large raw files """ if start: if end: return self.getContent()[start:end] return self.getContent()[start:] elif end: return self.getContent()[:end] return self.getContent()
def getMetaDataResource(self): """ Get the string meta data of this resource """ self._verifyTx() return self
def getContentResource(self): """ Get the resource that represents the content of this object """ self._verifyTx() p = self._path.normalize(".;content;no-traverse") return self._fetchResource(p)
def getImt(self): """ Returns the Internet Media Type of the raw file resource """ self._verifyTx() return 'text/xml'
def getValidationInfo(self): """ Get the validation information associated with this resource. """ self._verifyTx() return None
def getParent(self): """ Get the parent container of this resource """ self._verifyTx()
parentPath = self._path.getParentPath() return self._fetchResource(parentPath)
def getRoot(self): """ Get a reference to the system repository """ self._verifyTx() return self._cache.getResource(self._path._documentRoot)
def getAliases(self): """ Get a list of alias objects that reference this object """ self._verifyTx() aliases = [] for st in self._driver.getSystemModel().complete(None, Schema.ALIAS_REFERENCE, self.getAbsolutePath()):
aliases.append(self.fetchResource(st.subject+';no-traverse')) return aliases
def getExtFunctionsAndElements(self): """ All resource get to use the builtin functions. XsltDocuments override this to load the information from any associated document definitions. """ return Ft.Server.Server.Xslt.ExtFunctions.copy(), Ft.Server.Server.Xslt.ExtElements.copy()
##################################### #ACL Interfaces ##################################### def addAcl(self, aclKey, aclIdent, allowed=1): """ Add an acl identifier to the acl key. If the specified key does not exist on the resource this function has the same functionality of setAcl. """ self._verifyTx() self._verifyAclIdent(aclIdent) acl = self._driver.getAcl(self._path) if aclKey not in acl: acl[aclKey] = {} if allowed: acl[aclKey][aclIdent] = AclConstants.ALLOWED else: acl[aclKey][aclIdent] = AclConstants.DENIED self._driver.setAcl(self._path,acl) return
def getAcl(self, aclKey=None): """ Get a list of users and groups specified by the aclKey. If an aclKey is specified, then the results will be a list of dictionaries keyed by acl identifiers and with values of ALLOWED or DISALLOWED (from AclConstants). The values in the list of dictionaries could be inherited from the parent object. If no aclKey is specified, then the results will be a nested dictionary. The outer dictionary is keyed by all of the defined acl keys on this resource. Each value of the outer dictionary will be a dictionary identical to when this method is called with a aclKey. These results will not return any inherited values. """ self._verifyTx() return self._driver.getAcl(self._path, aclKey)
def getAclIdentifiers(self): """ Get a list of all acl identifiers for the current users. This is equivalent to performing an "expandGroups" of the current user. It will also add things such as "WORLD-GROUP" or "USER-GROUP" if they exist. """ self._verifyTx() return self._driver.getAclIdentifiers()
def getAclIdent(self): """ Get the ACL identifier for the current user (without expansion). """ self._verifyTx() return self._driver.getAclIdent()
def inheritAcl(self, aclKey): """ Remove the entire key from the ACL entry so that it is inherited again from its parent """ self._verifyTx() acl = self._driver.getAcl(self._path) if aclKey not in acl: return del acl[aclKey] self._driver.setAcl(self._path,acl) return
def removeAcl(self, aclKey, aclIdent): """ Remove the acl identifier from the acl key. If the specified aclKey is not present on the resource or the specified aclIdent is not in the key, then do nothing. Remember that entries inherited from the parent are *not* included in the acl on the actual resurce. In order to override inherited permissions, set to no access rather than trying to remove. """ self._verifyTx() self._verifyAclIdent(aclIdent) acl = self._driver.getAcl(self._path) if aclKey not in acl: return if aclIdent not in acl[aclKey]: return del acl[aclKey][aclIdent] self._driver.setAcl(self._path,acl) return
def setAcl(self, aclKey, aclIdent, allowed=1): """ Replace the aclKey with a single entry of aclIdent. """ self._verifyTx() self._verifyAclIdent(aclIdent) acl = self._driver.getAcl(self._path) if allowed: acl[aclKey] = {aclIdent:AclConstants.ALLOWED} else: acl[aclKey] = {aclIdent:AclConstants.DENIED} self._driver.setAcl(self._path,acl) return
def verifyAcl(self, aclKey, verifyTraverse=1): """ Test to see whether the current user (and the current users set of acl identifiers) is allowed to perform the specified action, aclKey, on the current object. If verifyTraverse is specified, then execute premissions are tested on all of the parents of this resource as well. """ self._verifyTx() return self._driver.verifyAcl(self._path, aclKey, verifyTraverse)
def _verifyAclIdent(self, aclIdent): """ This is a helper function to determine is an aclIdentifer is valid. """ if aclIdent in [AclConstants.WORLD_GROUP_NAME, AclConstants.USERS_GROUP_NAME, AclConstants.SUPER_USER_GROUP_NAME, AclConstants.ANONYMOUS_USER_NAME, AclConstants.OWNER]: return 1 if aclIdent in self.getRoot().getAllUserNames(): return 1 if aclIdent in self.getRoot().getAllGroupNames(): return 1 raise FtServerServerException(Error.INVALID_ACL_IDENT, aclIdent=aclIdent)
def getOwner(self): """ Get the owner of this resource. """ self._verifyTx() ownerName = self._driver.getSystemModel().complete(self.getAbsolutePath(), Schema.OWNER, None)[0].object return self.getRoot().fetchUserOrGroupByName(ownerName)
def setOwner(self, newOwner): """ Change the owner of this resource. """ self._verifyTx() self._driver.verifyAcl(self.getPath(), AclConstants.CHANGE_OWNER_ACCESS, 0) xu = SET_OWNER_XUPDATE%(str(FTSERVER_NAMESPACE), str(XLINK_NAMESPACE), newOwner.getName()) xu = XmlLib.MakeString(xu) self._driver.xupdateMetaData(self._path, xu) return
########################################## #XML Interfaces ##########################################
def applyXslt(self, chain, params=None, ignorePis=1, extParams=None, extModules=None): """ applies the specified chain of stylesheets (with the specified transformation parameters) using the "self" object as source chain - can be a list of transforms, in which case only one transform run will execute, with the list of transforms all used such that [a.xsl, b.xsl] is equivalent to adding an import of b.xsl to a.xsl and applying a.xsl can also be a list of lists of transforms, in which case a chain of transforms is run, one pass for each inner list. The output of each step in the chain is fed as the input to the next params - a dictionary giving the overridden top-level parameters for the transforms ignorePis - whether or not to ignore <xml-stylesheet processing instructions in the source document extParams - a special dictionary of parameters that allows the processor to communicate special values back to the caller extModules - a list of modules containing extension function and element implementations """ extModules = extModules or []
params = params or {} params[(RESERVED_NAMESPACE, 'display-path')] = self._path.displayPath params[(RESERVED_NAMESPACE, 'absolute-path')] = self._path.absolutePath params[(RESERVED_NAMESPACE, 'absolute-path-uri')] = self._path.absolutePathAsUri if self._path.absolutePath == '/': params[(RESERVED_NAMESPACE, 'base-path')] = self._basePath.absolutePath else: params[(RESERVED_NAMESPACE, 'base-path')] = self._basePath.absolutePath + '/' extParams = extParams or {} extParams[(RESERVED_NAMESPACE, 'path')] = self._path.absolutePath
#First map the stylesheets if not isinstance(chain, (list, tuple)): chain = (chain,) if not isinstance(chain[0], (list, tuple)): chain = (chain,)
#prep a base URI for figuring out the URI of the result # of applying each stylesheet in the chain base_uri = self._path.absolutePathAsUri if self.resourceType == ResourceTypes.ResourceType.CONTAINER and \ base_uri[-1] != '/': base_uri += '/'
rt = None for stylesheets in chain: p, rt, imt = self._xsltExecute(None, stylesheets, params, extParams, extModules, ignorePis) c = 0 while p.chainTo: #Chained-to stylesheets must be repo paths for now next = self.fetchResource(p.chainTo) #Generate URI of previous result, which is now the # source document. c += 1 prevResultUri = FtssInputSource.FTSS_RESOLVER.normalize( 'chain-result-' + str(c) + '.xml', base_uri) if p.chainParams: params.update(p.chainParams) p, rt, imt = self._xsltExecute( rt, [next], params, extParams, extModules, ignorePis, srcUri=prevResultUri) return rt, imt
def asDom(self, stripElements=None): """ Return the content of this object as a non-live DOM instance. This means that any mutations to the returned DOM object will not affect the content of this resource. An exception will be raised if the content cannot be parsed as XML. """ self._verifyTx() return FtssInputSource.NonvalidatingReader.parseString( self.getContent(), self._path.absolutePathAsUri, self._driver, stripElements = stripElements)
def toXPathContext(self,nss=None): """ Create an XPath Context with the src of this RawFile. nss is a dictionary of namespace definitions to include in the context. """ self._verifyTx() return self._driver.getContext(self._path,nss)
def xUpdate(self, updateSrc): """ Allows XML content to be updated with the XUpdate protocol. updateSrc is a string that represents the XUpdate to be applied to the resource. extraNss is a dict of additional namespace bindings to pass to the XUpdate processor, if necessary. """ xureader = XUpdate.Reader()
isrc = FtssInputSource.FtssInputSourceFactory.fromString( updateSrc, self._path.absolutePath, self._driver ) xu = xureader.fromSrc(isrc) processor = XUpdate.Processor() dom = self.asDom() processor.execute(dom, xu)
st = cStringIO.StringIO() Print(dom, stream=st) self.setContent(st.getvalue()) return
##################################### #Query Interfaces ##################################### def hasResource(self, path): """ Query if the system has a resource specified by the path. No exception will be raised by this function. If the current user cannot access the resource or the resource does not exist in the repository, then the results will be 0. If the resource does exist, then the results will be the integer resource type of the resource (see Ft.Server.Common.ResourceTypes.ResourceTypes). """ self._verifyTx() path = self._basePath.normalize(path) if self._driver.hasResource(path): return self._driver.getType(path) return 0
##################################### #Retrieval Interfaces ##################################### def fetchResource(self, path, traverseAliases=None): """ Fetch a resource from the system. path is a string. The traverseAliases parameter is deprecated and the new ";traverse" path arguments should be used. As an example, where before you could call: resource.fetchResource('path',1) now you would call resource.fetchResource('path;traverse') """ self._verifyTx() if (traverseAliases != None): warnings.warn("You are using a deprecated traverse alias feature. Please specify with path arguments ;traverse or ;no-traverse", DeprecationWarning, 2) if traverseAliases: path += ";traverse" else: path += ";no-traverse" path = self._basePath.normalize(path) return self._fetchResource(path)
########################################## #Retrieval Interfaces ##########################################
def _fetchResource(self, path): """ Internal call to fetch a resource. path is an instance of PathImp. """
if path.displayPath == '/' and path.resourceType != ResourceTypes.RESOURCE_METADATA: return self.getRoot()
obj = self._cache.getResource(path) if obj is not None: return obj
self._driver.verifyAcl(path, AclConstants.READ_ACCESS, 1)
if path.resourceType == ResourceTypes.RESOURCE_METADATA: #Get the MetaData object return ResourceMetaDataImp(path, self._driver, self._cache)
rt = self._driver.getType(path)
if rt == ResourceTypes.ResourceType.RAW_FILE: import RawFileImp obj = RawFileImp.RawFileImp(path, self._driver, self._cache) elif rt == ResourceTypes.ResourceType.URI_REFERENCE_FILE: import UriReferenceFileImp obj = UriReferenceFileImp.UriReferenceFileImp(path, self._driver, self._cache) elif rt == ResourceTypes.ResourceType.XML_DOCUMENT: import XmlDocumentImp obj = XmlDocumentImp.XmlDocumentImp(path, self._driver, self._cache) elif rt == ResourceTypes.ResourceType.COMMAND: import CommandImp obj = CommandImp.CommandImp(path, self._driver, self._cache) elif rt == ResourceTypes.ResourceType.SERVER: import ServerImp obj = ServerImp.ServerImp(path, self._driver, self._cache) elif rt == ResourceTypes.ResourceType.XSLT_DOCUMENT: import XsltDocumentImp obj = XsltDocumentImp.XsltDocumentImp(path, self._driver, self._cache) elif rt == ResourceTypes.ResourceType.RDF_DOCUMENT: import RdfDocumentImp obj = RdfDocumentImp.RdfDocumentImp(path, self._driver, self._cache) elif rt == ResourceTypes.ResourceType.CONTAINER: import ContainerImp obj = ContainerImp.ContainerImp(path, self._driver, self._cache) elif rt == ResourceTypes.ResourceType.GROUP: import GroupImp obj = GroupImp.GroupImp(path, self._driver, self._cache) elif rt == ResourceTypes.ResourceType.USER: import UserImp obj = UserImp.UserImp(path, self._driver, self._cache) elif rt == ResourceTypes.ResourceType.XPATH_DOCUMENT_DEFINITION: import XPathDocumentDefinitionImp obj = XPathDocumentDefinitionImp.XPathDocumentDefinitionImp(path, self._driver, self._cache) elif rt == ResourceTypes.ResourceType.XSLT_DOCUMENT_DEFINITION: import XsltDocumentDefinitionImp obj = XsltDocumentDefinitionImp.XsltDocumentDefinitionImp(path, self._driver, self._cache) elif rt == ResourceTypes.ResourceType.ALIAS: import AliasImp obj = AliasImp.AliasImp(path, self._driver, self._cache) elif rt == ResourceTypes.ResourceType.SCHEMATRON_DOCUMENT: import SchematronDocumentImp obj = SchematronDocumentImp.SchematronDocumentImp(path, self._driver, self._cache) else: raise FtServerServerException(Error.UNKNOWN_RESOURCE_TYPE, type=rt) return obj
########################################## #Mutation Interfaces ########################################## def setContent(self,src): """ Set the string content of this resource. """ self._verifyTx() self._driver.updateResourceContent(self._path, src) return
def delete(self): """ Delete this object from the repository. """ self._verifyTx() self._driver.verifyDeleteResource(self._path) self._delete()
self._cache.unregisterResource(self._path)
#Just incase mdPath = self._path.normalize('.;metadata;no-traverse') self._cache.unregisterResource(mdPath) conPath = self._path.normalize('.;content;no-traverse') self._cache.unregisterResource(conPath)
self._deleted = 1 return
################################### #Creation Interfaces ################################### def addAlias(self,path,docDef = None): """ Adds an alias for this resource to the repository. path is the string path of the new alias. docDef is the document definition to associate with the new alias. """ self._verifyTx() path = self._basePath.normalize(path) if docDef: docDefPath = self._basePath.normalize(docDef) if self._driver.getType(docDefPath) not in ResourceTypes.DOCUMENT_DEFINITIONS: raise FtServerServerException(Error.INVALID_PATH, path=docDefPath.displayPath, type='Document Definition') else: docDefPath = None
import AliasImp md, content = AliasImp.NewAliasXml(self._driver, self._path.absolutePath, path.name, {}, self._driver.getAclIdent(), docDefPath and docDefPath.absolutePath or None)
self._driver.createResource(path, md, content) return self._fetchResource(path)
###################################### #Delete Interface ###################################### def removeAlias(self,path): """ Removes the specified alias for this resource. """ self._verifyTx() path = self._basePath.normalize(path + ';no-traverse') res = self._fetchResource(path) res.delete() return
######################################## #RDF Interfaces ########################################
def getModel(self): """ Retrieves the common model associated w/ the repository """ self._verifyTx() return self._driver.getModel(self._path)
def addLiteralProperty(self, predicate, object, scope='', statementUri=''): """ Adds a statement about this repository object, with a literal property, to the model """ stmt = Statement.Statement(self.getAbsolutePath(), predicate, object, scope = scope, statementUri=statementUri, objectType=OBJECT_TYPE_LITERAL) self._driver.getModel(self._path).add([stmt]) return stmt
def addResourceProperty(self, predicate, object, scope='', statementUri=''): """ Adds a statement about this repository object, with a resource property, to the model """ stmt = Statement.Statement(self.getAbsolutePath(), predicate, object.getUri(), scope=scope, statementUri=statementUri, objectType=OBJECT_TYPE_RESOURCE) self._driver.getModel(self._path).add([stmt]) return stmt
def removeResourceProperty(self, predicate, object): """ Remove a statement about this repository object, with a resource preoperty, from the model """ self._driver.getModel(self._path).removePattern(self._path.absolutePath, predicate,object.getUri()) return
def removeLiteralProperty(self, predicate, object): """ Removes a statement about this repository object, with a literal property, from the model """ self._driver.getModel(self._path).removePattern(self._path.absolutePath,predicate,object)
def getStatementsAbout(self): """ Returns all statements about this object in the model """ return self._driver.getModel(self._path).complete(self._path, None, None)
def getStatementsGeneratedBy(self): """ Returns all statements in the model generated by this object """ return self._driver.getModel(self._path).complete(None, None, None, scope=self._path)
######################################## #Temporary file Interfaces ######################################## def markTemporary(self, timeToLive): """ Mark this resource as temporary. Temporary objects will be removed from the repository when their timeToLive has expired and purgeTemporaryResources() is called on the repository. Time to live is seconds from now. purgeTemporaryResources() is most often called from the controller and is based on the controller configuration option TemporaryReapInterval. """ self.getRoot().setPathTemporary(self._path.absolutePath, timeToLive) return
########################################## #String interfaces ########################################## def __str__(self): return "<%s at %x path='%s'>" % (ResourceTypes.g_resourceTypeMap[self.getResourceType()], id(self), self._path.absolutePath)
###################################### #Internal Interfaces ######################################
def _verifyTx(self): self._driver._verifyTx() if self._deleted: raise FtServerServerException(Error.OBJECT_DELETED, path=self._path)
def _delete(self): self._driver.deleteResource(self._path) return
def _xsltExecute(self, src, stylesheets, params, extParams, extModules, ignorePis, srcUri=''): """ Applies an XSLT stylesheet to this object, or to the given src string (if any). If src is given, srcUri should also be given, to establish the URI of the src. srcUri is treated as a URI reference, resolved against this object's URI. If multiple stylesheets are given, they are chained (each is applied to the result of the previous transformation). """
p = Ft.Xml.Xslt.Processor.Processor() p.extensionParams = extParams
# Register our general extension modules p.registerExtensionModules(['Ft.Server.Server.Xslt']+extModules)
p._repository = self.getRoot()
p.setDocumentReader(FtssInputSource.NonvalidatingReader)
for s in stylesheets: #print "stylesheet %r" % s if isinstance(s, (str, unicode)): #print "creating FtssInputSource from URI %r" % self._path.absolutePathAsUri isrc = FtssInputSource.FtssInputSourceFactory.fromUri( self._path.absolutePathAsUri, self._driver) #print "using it to get a new FtssInputSource for system ID %r" % s isrc = isrc.resolve(s, '', 'REPO APPLYXSLT') #print "new FtssInputSource has uri %r" % isrc.uri p.appendStylesheet(isrc) elif hasattr(s, 'toStylesheet'): #A document reference p.appendStylesheetInstance(s.toStylesheet(self)) elif hasattr(s, 'asStylesheet'): #A reference to a document in the system p.appendStylesheetInstance(s.asStylesheet())
#See if it has any ext functions f, e = s.getExtFunctionsAndElements() p.extFunctions.update(f) p.extElements.update(e)
p.inputSourceFactory = FtssInputSource._FtssInputSourceFactory( self._driver)
if src: uri = FtssInputSource.FTSS_RESOLVER.normalize(srcUri, self._path.absolutePathAsUri) isrc = p.inputSourceFactory.fromString(src, uri) rt = p.run(isrc, ignorePis=ignorePis, topLevelParams=params) else: uri = self._path.absolutePathAsUri if self._path.resourceType == ResourceTypes.RESOURCE_METADATA: uri += ';metadata' uri += ';no-traverse' #print "!!! creating FtssInputSource from URI %r" % uri isrc = p.inputSourceFactory.fromUri(uri, self._driver) rt = p.runNode(self.asDom(), uri, ignorePis=ignorePis, topLevelParams=params, docInputSource=isrc)
if extParams is not None and hasattr(p, 'extensionParams'): extParams.update(p.extensionParams)
imt = p._lastOutputParams.mediaType return p, rt, imt
SET_OWNER_XUPDATE="""<xupdate:modifications version="1.0" xmlns:xupdate="http://www.xmldb.org/xupdate" xmlns:ftss="%s" xmlns:xlink="%s" > <xupdate:update select="/ftss:MetaData/ftss:Owner">%s</xupdate:update> </xupdate:modifications>"""
UPDATE_TIME_TO_LIVE_XUPDATE="""<?xml version="1.0"?> <xupdate:modifications version="1.0" xmlns:xupdate="http://www.xmldb.org/xupdate" xmlns:ftss="%s" xmlns:xlink="%s" > <xupdate:update select="/ftss:MetaData/ftss:TimeToLive">%s</xupdate:update> </xupdate:modifications> """
SET_TIME_TO_LIVE_XUPDATE="""<?xml version="1.0"?> <xupdate:modifications version="1.0" xmlns:xupdate="http://www.xmldb.org/xupdate" xmlns:ftss="%s" xmlns:xlink="%s" > <xupdate:append select="/ftss:MetaData"><ftss:TimeToLive>%s</ftss:TimeToLive></xupdate:append> </xupdate:modifications> """
|