source: exist/trunk/python/ndgUtils/models/MolesEntity.py @ 4427

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/exist/trunk/python/ndgUtils/models/MolesEntity.py@4427
Revision 4427, 13.7 KB checked in by cbyrom, 11 years ago (diff)

Upgrade the various 'list' xqueries - to nest all results in a single
root element - so that only one document need be retrieved to get all
results + adjust ndgDirectory to cope with processing the new results +
fix the various namespaces mentioned in the codebase to map to the
current atom/moles ones.

Line 
1'''
2 Class representing moles data that is too structured to be included in the basic Atom elements
3 
4 @author: C Byrom, Tessella Jun 2008
5'''
6try: #python 2.5
7    from xml.etree import cElementTree as ET
8except ImportError:
9    try:
10        # if you've installed it yourself it comes this way
11        import cElementTree as ET
12    except ImportError:
13        # if you've egged it this is the way it comes
14        from ndgUtils.elementtree import cElementTree as ET
15import sys, logging, re, datetime
16from ndgUtils.vocabtermdata import VocabTermData as VTD
17from utilities import getTripleData, escapeSpecialCharacters, tidyUpParameters
18
19class DeploymentLink(object):
20   
21    def __init__(self, url, vocabUrl, title=None):
22        '''
23        Constructor - initialise the deployment link object
24        '''
25        self.url = url
26        self.vocabUrl = vocabUrl
27        self.title = title
28       
29    def toXML(self):
30        logging.info("Creating XML version of Deployment link element")
31        link = self.toET()
32        tree = ET.ElementTree(link)
33        logging.info("XML version of Deployment link element created")
34        return tree
35       
36    def toET(self):
37        logging.info("Creating ElementTree version of Deployment link element")
38        link = ET.Element("link")
39        link.attrib["href"] = self.url
40        link.attrib["rel"] = self.vocabUrl
41        if self.title:
42            link.attrib["title"] = tidyUpParameters(self.title)
43
44        logging.info("ElementTree version of Deployment element link created")
45        return link
46
47    def __cmp__(self, link):
48        if not link:
49            return -1
50       
51        if isinstance(link, DeploymentLink):
52            if link.url == self.url and \
53                link.vocabUrl == self.vocabUrl and \
54                link.title == self.title:
55                return 0
56
57        return 1
58   
59class Deployments(object):
60   
61    def __init__(self, id, deploymentLinks, startDate=None, endDate=None):
62        '''
63        Constructor - initialise the deployments object
64        '''
65        self.id = id
66        # ensure deployments is an array
67        self.deploymentLinks = []
68        if deploymentLinks:
69            self.addDeploymentLinks(deploymentLinks)
70        self.startDate = startDate
71        self.endDate = endDate
72       
73    def toXML(self):
74        logging.info("Creating XML version of Deployments element")
75        deployments = self.toET()
76        tree = ET.ElementTree(deployments)
77        logging.info("XML version of Deployments element created")
78        return tree
79
80
81    def toET(self):
82        logging.info("Creating ElementTree version of Deployments element")
83        deploymentElement = ET.Element("moles:deployment")
84        deploymentElement.attrib["id"] = self.id
85        startElement = ET.SubElement(deploymentElement, "moles:startDate")
86        startElement.text = self.startDate
87        endElement = ET.SubElement(deploymentElement, "moles:endDate")
88        endElement.text = self.endDate
89       
90        for deploymentLink in self.deploymentLinks:
91            deploymentElement.append(deploymentLink.toET())
92        logging.info("ElementTree version of Deployments element created")
93        return deploymentElement
94   
95   
96    def addDeploymentLinks(self, deploymentLinks):
97        logging.info("Adding deployment links to deployment")
98        if type(deploymentLinks) != type([]):
99            deploymentLinks = [deploymentLinks]
100        for deploymentLink in deploymentLinks:
101            # do uniqueness check
102            if deploymentLink not in self.deploymentLinks:
103                self.deploymentLinks.append(deploymentLink)
104        logging.info("Deployment links added to deployment")
105       
106
107class MolesEntity(object):
108   
109    # URL which points to the browse service - NB ensure this is properly defined
110    BROWSE_URL = "http://ndg.badc.rl.ac.uk:8080/view"
111   
112    def __init__(self):
113        '''
114        Constructor - initialise the atom variables
115        '''
116        logging.info("Initialising MolesEntity")
117
118        # an array of Atom.Person objects
119        self.responsibleParties = []
120        self.deployments = {}
121        self.abbreviation = None
122        self.providerID = None
123        self.createdDate = None
124               
125        self.datasetLanguage = 'English'
126        self.metadataLanguage = 'English'
127       
128        # helper arrays to produce summary info for atom in templates
129        self.activities = []
130        self.obs = []
131        self.dpts = []
132        logging.info("MolesEntity initialised")     
133
134
135    def addResponsibleParty(self, partyVals):
136        '''
137        Add a responsible party - using the input string format,
138        ' name | uri | role '
139        '''
140        logging.debug("Adding responsible party data")
141        from ndgUtils.models.Atom import Person
142        if type(partyVals) is not list:
143            partyVals = [partyVals]
144       
145        for vals in partyVals:
146            rp = Person(personType = Person.RESPONSIBLE_PARTY_TYPE)
147            rp.fromString(vals)
148            self.responsibleParties.append(rp)
149        logging.debug("Finished adding responsible party data")
150
151
152
153    def addDeployment(self, deploymentID, startDate=None, endDate=None):
154        '''
155        Add a deployment to the dictionary - ensuring it is unique and has been formatted and tidied appropriately
156        @param deploymentID: ID of the deployment - acts as a key in the deployments dictionary
157        @keyword startDate: optional start date
158        @keyword endDate: optional end date
159        '''
160        logging.info("Adding new deployment data to moles entity")
161        self.deployments[deploymentID] = Deployments(deploymentID, None, startDate=startDate, endDate=endDate)
162        logging.info("New deployment data added to moles entity")
163
164
165    def addDeploymentLink(self, deploymentID, contentURL, vocabURL, title=None):
166        '''
167        Add a deployment link to the dictionary - ensuring it is unique and has been formatted and tidied appropriately
168        @param deploymentID: ID of the deployment - acts as a key in the deployments dictionary
169        @param contentURL: url to deployment content
170        @param vocabURL: url to vocab term identifying type of deployment content
171        @keyword title: title string to display with deployment link
172        '''
173        logging.info("Adding new deployment link data to moles entity")
174        logging.debug("contentURL: '%s', vocabURL: '%s', title: '%s'" %(contentURL, vocabURL, title))
175        deploymentLink = DeploymentLink(contentURL, vocabURL, title=title)
176
177        self._addDeploymentDetails(deploymentLink)
178
179        if deploymentID not in self.deployments:
180            logging.debug("Creating new deployment type: %s" %deploymentID)
181            self.deployments[deploymentID] = Deployments(deploymentID, deploymentLink)
182        else:
183            logging.debug("Adding to existing deployment")
184            deployment = self.deployments[deploymentID]
185            deployment.addDeploymentLinks(deploymentLink)
186
187        logging.info("New deployment link data added to moles entity")
188
189       
190    def _addDeploymentDetails(self, deploymentLink):
191        '''
192        Add deployment details to local arrays for easy access by templates
193        '''
194        deploymentType = None
195        # first, determine type of deployment
196        if deploymentLink.vocabUrl.startswith(VTD.TERM_DATA[VTD.ACTIVITY_TERM].vocabURL):
197            deploymentType = self.activities
198        elif deploymentLink.vocabUrl.startswith(VTD.TERM_DATA[VTD.OBS_TERM].vocabURL):
199            deploymentType = self.obs
200        elif deploymentLink.vocabUrl.startswith(VTD.TERM_DATA[VTD.DPT_TERM].vocabURL):
201            deploymentType = self.dpts
202        else:
203            return
204
205        # Now check if this has already been added; return if so
206        for link in deploymentType:
207            if link == deploymentLink:
208                return
209
210        deploymentType.append(deploymentLink)
211
212       
213    def toXML(self):
214        '''
215        Convert the atom into XML representation and return this
216        @return: xml version of atom
217        '''
218        logging.info("Creating formatted XML version of MolesEntity")
219        molesEntity = ET.Element("moles:entity")
220        molesEntity.attrib["xmlns:moles"] = "http://ndg.nerc.ac.uk/schema/moles2beta"
221       
222        molesISO = ET.SubElement(molesEntity, "moles:molesISO")
223        datasetLanguage = ET.SubElement(molesISO, "moles:datasetLanguage")
224        datasetLanguage.text = self.datasetLanguage
225        metadataLanguage = ET.SubElement(molesISO, "moles:metadataLanguage")
226        metadataLanguage.text = self.metadataLanguage
227
228        if self.responsibleParties:
229            rpElement = ET.SubElement(molesISO, "moles:responsibleParties")
230            logging.info("Adding responsible parties info")
231            for party in self.responsibleParties:
232                rpElement.append(party.toXML())
233
234        if self.abbreviation:
235            logging.info("Adding abbreviation element")
236            abbreviationElement = ET.SubElement(molesISO, "moles:abbreviation")
237            abbreviationElement.text = self.abbreviation
238
239        if self.providerID:
240            logging.info("Adding providerID element")
241            subElement = ET.SubElement(molesISO, "moles:providerID")
242            subElement.text = self.providerID
243
244        if self.deployments:
245            deploymentsElement = ET.SubElement(molesISO, "moles:deployments")
246           
247            for deployment in self.deployments:
248                deploymentsElement.append(self.deployments[deployment].toET())
249           
250        # if there's a created date already defined, use this, otherwise assume this is the creation point
251        # so use current time
252        if not self.createdDate:
253            self.createdDate = datetime.datetime.today().strftime("%Y-%m-%dT%H:%M:%SZ")
254
255        createdElement = ET.SubElement(molesISO, "moles:created")
256        createdElement.text = self.createdDate
257
258        logging.info("XML version of MolesEntity created")
259        return molesEntity
260
261
262    def fromET(self, tree):
263        '''
264        Initialise MolesEntity object using an elementtree
265        @param tree: ElementTree with moles entity data
266        '''
267        logging.info("Ingesting data from ElementTree object")
268       
269        authorElements = tree.findall('molesISO/responsibleParties/responsibleParty')
270        from ndgUtils.models.Atom import Person
271        for authorElement in authorElements:
272            logging.debug("Adding atom author data")
273            author = Person(personType = Person.RESPONSIBLE_PARTY_TYPE)
274            author.fromETElement(authorElement)
275            self.responsibleParties.append(author)
276               
277        self.abbreviation = tree.findtext('molesISO/abbreviation')
278
279        self.providerID = tree.findtext('molesISO/providerID')
280
281        self.datasetLanguage = tree.findtext('molesISO/datasetLanguage')
282        self.metadataLanguage = tree.findtext('molesISO/metadataLanguage')
283
284        createdDate = tree.findtext('molesISO/created')
285        if createdDate:
286            logging.debug("Adding created date")
287            self.createdDate = createdDate
288           
289        deploymentElements = tree.findall('molesISO/deployments/deployment')
290        for deploymentElement in deploymentElements:
291            self._addDeploymentData(deploymentElement)
292           
293        logging.info("Data ingested from tree")
294
295
296    def _addDeploymentData(self, deploymentElement):
297        '''
298        Parse a deployment element and extract all the required data from it
299        @param deploymentElement: ElementTree element representing a deployment element
300        '''
301        id = deploymentElement.attrib.get('id')
302        startDate = deploymentElement.findtext('startDate')
303        endDate = deploymentElement.findtext('endDate')
304        linkElements = deploymentElement.findall('link')
305        self.addDeployment(id, startDate, endDate)
306        for linkElement in linkElements:
307            contentURL = linkElement.attrib.get('href')
308            vocabURL = linkElement.attrib.get('rel')
309            title = linkElement.attrib.get('title')
310            self.addDeploymentLink(id, contentURL, vocabURL, title = title)
311           
312           
313    def fromString(self, xmlString):
314        '''
315        Initialise MolesEntity object using an xmlString
316        @param xmlString: representation of atom as an XML string
317        '''
318        logging.info("Ingesting data from XML string")
319       
320        # firstly, remove any namespaces used - to avoid problems with elementtree
321        logging.debug("Stripping moles namespace from string to allow easy handling with elementtree")
322        xmlString = xmlString.replace('moles:', '')
323
324        # now create elementtree with the XML string
325        logging.debug("Create elementtree instance with XML string")
326        tree = ET.fromstring(xmlString)
327        self.fromET(tree)
328        logging.info("Completed data ingest from XML string")
329
330       
331    def setAttribute(self, attributeName, attributeValue):
332        '''
333        Set the value of an atom attribute - and do some basic tidying up of the string content
334        - to escape any XML unfriendly characters
335        @param attributeName: name of the attribute whose value to set
336        @param attributeValue: value to set the attribute to 
337        '''
338        logging.debug("Setting attribute, %s, to %s" %(attributeName, attributeValue))
339        origValue = attributeValue
340       
341        # escape any special characters if a value has been specified
342        # NB, need to cope with both single values and arrays
343        if attributeValue:
344            if type(attributeValue) is list:
345                newVals = []
346                for val in attributeValue:
347                    newVals.append(escapeSpecialCharacters(val))
348                attributeValue = newVals
349            else:
350                attributeValue = escapeSpecialCharacters(attributeValue) 
351        setattr(self, attributeName, attributeValue)
Note: See TracBrowser for help on using the repository browser.