Commit 7bf44fe5 authored by Christian Ledermann's avatar Christian Ledermann

move from lists to generators to fetch the contents of a container or kml, use...

move from lists to generators to fetch the contents of a container or kml, use getter and setter for feature.styleUrl
parent f67a7e85
...@@ -19,13 +19,9 @@ This library only implements a subset of Atom that is useful with KML ...@@ -19,13 +19,9 @@ This library only implements a subset of Atom that is useful with KML
import logging import logging
logger = logging.getLogger('fastkml.atom') logger = logging.getLogger('fastkml.atom')
from config import etree
try: NS = '{http://www.w3.org/2005/Atom}'
from lxml import etree
LXML = True
except ImportError:
import xml.etree.ElementTree as etree
LXML = False
import re import re
regex = r"^[a-zA-Z0-9._%-]+@([a-zA-Z0-9-]+\.)*[a-zA-Z]{2,4}$" regex = r"^[a-zA-Z0-9._%-]+@([a-zA-Z0-9-]+\.)*[a-zA-Z]{2,4}$"
...@@ -75,7 +71,7 @@ class Link(object): ...@@ -75,7 +71,7 @@ class Link(object):
def __init__(self, ns=None, href=None, rel=None, type=None, def __init__(self, ns=None, href=None, rel=None, type=None,
hreflang=None, title=None, lenght=None): hreflang=None, title=None, lenght=None):
if ns == None: if ns == None:
self.ns = '{http://www.w3.org/2005/Atom}' self.ns = NS
else: else:
self.ns = ns self.ns = ns
self.href = href self.href = href
...@@ -129,6 +125,7 @@ class _Person(object): ...@@ -129,6 +125,7 @@ class _Person(object):
entity. It has one required element, name, and two optional elements: entity. It has one required element, name, and two optional elements:
uri, email. uri, email.
""" """
__name__ = None
ns = None ns = None
name = None name = None
...@@ -142,7 +139,7 @@ class _Person(object): ...@@ -142,7 +139,7 @@ class _Person(object):
def __init__(self, ns=None, name=None, uri=None, email=None): def __init__(self, ns=None, name=None, uri=None, email=None):
if ns == None: if ns == None:
self.ns = '{http://www.w3.org/2005/Atom}' self.ns = NS
else: else:
self.ns = ns self.ns = ns
self.name = name self.name = name
......
...@@ -35,7 +35,7 @@ class _BaseObject(object): ...@@ -35,7 +35,7 @@ class _BaseObject(object):
if self.targetId: if self.targetId:
element.set('targetId', self.targetId) element.set('targetId', self.targetId)
else: else:
raise NotImplementedError raise NotImplementedError("Call of abstract base class, subclasses implement this!")
return element return element
...@@ -44,9 +44,17 @@ class _BaseObject(object): ...@@ -44,9 +44,17 @@ class _BaseObject(object):
def from_element(self, element): def from_element(self, element):
if self.ns + self.__name__ != element.tag: if self.ns + self.__name__ != element.tag:
raise TypeError raise TypeError("Call of abstract base class, subclasses implement this!")
else: else:
if element.get('id'): if element.get('id'):
self.id = element.get('id') self.id = element.get('id')
if element.get('targetId'): if element.get('targetId'):
self.targetId = element.get('targetId') self.targetId = element.get('targetId')
def to_string(self, prettyprint=True):
""" Return the KML Object as serialized xml """
if config.LXML and prettyprint:
return etree.tostring(self.etree_element(), encoding='utf-8',
pretty_print=True)
else:
return etree.tostring(self.etree_element(), encoding='utf-8')
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""frequently used constants and abstract base classes""" """frequently used constants and abstract base classes"""
try:
from lxml import etree
LXML = True
except ImportError:
import xml.etree.ElementTree as etree
LXML = False
NS = '{http://www.opengis.net/kml/2.2}' NS = '{http://www.opengis.net/kml/2.2}'
...@@ -15,19 +15,19 @@ from geometry import MultiPoint, MultiLineString, MultiPolygon ...@@ -15,19 +15,19 @@ from geometry import MultiPoint, MultiLineString, MultiPolygon
from geometry import LinearRing from geometry import LinearRing
from datetime import datetime, date from datetime import datetime, date
# note that there are some ISO 8601 timeparsers at pypi
# but in my tests all of them had some errors so we rely on the
# tried and tested dateutil here which is more stable. As a side effect
# we can also parse non ISO compliant dateTimes
import dateutil.parser import dateutil.parser
import logging import logging
logger = logging.getLogger('fastkml.kml') logger = logging.getLogger('fastkml.kml')
try:
from lxml import etree
LXML = True
except ImportError:
import xml.etree.ElementTree as etree
LXML = False
import config import config
from config import etree
from base import _BaseObject from base import _BaseObject
from styles import StyleUrl, Style, StyleMap, _StyleSelector from styles import StyleUrl, Style, StyleMap, _StyleSelector
...@@ -80,24 +80,29 @@ class KML(object): ...@@ -80,24 +80,29 @@ class KML(object):
def to_string(self, prettyprint=False): def to_string(self, prettyprint=False):
""" Returm the KML Object as xml """ """ Return the KML Object as serialized xml """
if LXML and prettyprint: if config.LXML and prettyprint:
return etree.tostring(self.etree_element(), encoding='utf-8', return etree.tostring(self.etree_element(), encoding='utf-8',
pretty_print=True) pretty_print=True)
else: else:
return etree.tostring(self.etree_element(), encoding='utf-8') return etree.tostring(self.etree_element(), encoding='utf-8')
def features(self): def features(self):
""" return a list of features """ """ iterate over features """
#XXX yield feature, test if they are valid features for feature in self._features:
return self._features if isinstance(feature, (Document, Folder, Placemark)):
yield feature
else:
raise TypeError(
"Features must be instances of (Document, Folder, Placemark)")
def append(self, kmlobj): def append(self, kmlobj):
""" append a feature """ """ append a feature """
if isinstance(kmlobj, (Document, Folder, Placemark)): if isinstance(kmlobj, (Document, Folder, Placemark)):
self._features.append(kmlobj) self._features.append(kmlobj)
else: else:
raise TypeError raise TypeError(
"Features must be instances of (Document, Folder, Placemark)")
class _Feature(_BaseObject): class _Feature(_BaseObject):
""" """
...@@ -110,6 +115,7 @@ class _Feature(_BaseObject): ...@@ -110,6 +115,7 @@ class _Feature(_BaseObject):
#PhotoOverlay, #PhotoOverlay,
#ScreenOverlay #ScreenOverlay
""" """
name = None
#User-defined text displayed in the 3D viewer as the label for the #User-defined text displayed in the 3D viewer as the label for the
#object (for example, for a Placemark, Folder, or NetworkLink). #object (for example, for a Placemark, Folder, or NetworkLink).
description = None description = None
...@@ -123,7 +129,7 @@ class _Feature(_BaseObject): ...@@ -123,7 +129,7 @@ class _Feature(_BaseObject):
#Boolean value. Specifies whether a Document or Folder appears #Boolean value. Specifies whether a Document or Folder appears
#closed or open when first loaded into the Places panel. #closed or open when first loaded into the Places panel.
#0=collapsed (the default), 1=expanded. #0=collapsed (the default), 1=expanded.
styleUrl = None _styleUrl = None
#URL of a <Style> or <StyleMap> defined in a Document. #URL of a <Style> or <StyleMap> defined in a Document.
#If the style is in the same file, use a # reference. #If the style is in the same file, use a # reference.
#If the style is defined in an external file, use a full URL #If the style is defined in an external file, use a full URL
...@@ -137,18 +143,37 @@ class _Feature(_BaseObject): ...@@ -137,18 +143,37 @@ class _Feature(_BaseObject):
def __init__(self, ns=None, id=None, name=None, description=None, def __init__(self, ns=None, id=None, name=None, description=None,
styles=None, styleUrl=None): styles=None, styleUrl=None):
self.id = id super(_Feature, self).__init__(ns, id)
self.name=name self.name=name
self.description=description self.description=description
self.styleUrl = styleUrl if styleUrl is not None:
self.styleUrl = styleUrl
self._styles = [] self._styles = []
if styles: if styles:
for style in styles: for style in styles:
self.append_style(style) self.append_style(style)
if ns == None:
self.ns = config.NS @property
def styleUrl(self):
""" Returns the url only, not a full StyleUrl object.
if you need the full StyleUrl use _styleUrl """
if isinstance(self._styleUrl, StyleUrl):
return self._styleUrl.url
@styleUrl.setter
def styleUrl(self, styleurl):
""" you may pass a StyleUrl Object, a string or None """
if isinstance(styleurl, StyleUrl):
self._styleUrl = styleurl
elif isinstance(styleurl, basestring):
s = StyleUrl(self.ns, url=styleurl)
self._styleUrl = s
elif styleurl is None:
self._styleUrl = None
else: else:
self.ns = ns raise ValueError
def append_style(self, style): def append_style(self, style):
""" append a style to the feature """ """ append a style to the feature """
...@@ -167,33 +192,28 @@ class _Feature(_BaseObject): ...@@ -167,33 +192,28 @@ class _Feature(_BaseObject):
def etree_element(self): def etree_element(self):
if self.__name__: element = super(_Feature, self).etree_element()
element = etree.Element(self.ns + self.__name__) if self.name:
if self.id: name = etree.SubElement(element, "%sname" %self.ns)
element.set('id', self.id) name.text = self.name
if self.name: if self.description:
name = etree.SubElement(element, "%sname" %self.ns) description =etree.SubElement(element, "%sdescription" %self.ns)
name.text = self.name description.text = self.description
if self.description: visibility = etree.SubElement(element, "%svisibility" %self.ns)
description =etree.SubElement(element, "%sdescription" %self.ns) visibility.text = str(self.visibility)
description.text = self.description isopen = etree.SubElement(element, "%sopen" %self.ns)
visibility = etree.SubElement(element, "%svisibility" %self.ns) isopen.text = str(self.isopen)
visibility.text = str(self.visibility) if self._styleUrl is not None:
isopen = etree.SubElement(element, "%sopen" %self.ns) element.append(self._styleUrl.etree_element())
isopen.text = str(self.isopen) for style in self.styles():
if self.styleUrl: element.append(style.etree_element())
styleUrl = StyleUrl( self.ns, self.styleUrl) if (self._time_span is not None) and (self._time_stamp is not None):
element.append(styleUrl.etree_element()) raise ValueError
for style in self.styles(): #elif self._time_span:
element.append(style.etree_element()) # timespan = TimeStamp(self.ns, begin=self._time_span[0][0],
if (self._time_span is not None) and (self._time_stamp is not None): # begin_res=self._time_span[0][1])
raise ValueError
#elif self._time_span:
# timespan = TimeStamp(self.ns, begin=self._time_span[0][0],
# begin_res=self._time_span[0][1])
else:
raise NotImplementedError
return element return element
...@@ -226,10 +246,11 @@ class _Feature(_BaseObject): ...@@ -226,10 +246,11 @@ class _Feature(_BaseObject):
s.from_element(style) s.from_element(style)
self.append_style(s) self.append_style(s)
style_url = element.find('%sstyleUrl' % self.ns) style_url = element.find('%sstyleUrl' % self.ns)
if style_url: if style_url is not None:
s = StyleUrl(self.ns) s = StyleUrl(self.ns)
s.from_element(style_url) s.from_element(style_url)
self.styleUrl = s.url self._styleUrl = s
#XXX Timespan/stamp
...@@ -248,14 +269,15 @@ class _Container(_Feature): ...@@ -248,14 +269,15 @@ class _Container(_Feature):
def __init__(self, ns=None, id=None, name=None, description=None): def __init__(self, ns=None, id=None, name=None, description=None):
super(_Container, self).__init__(ns, id, name, description) super(_Container, self).__init__(ns, id, name, description)
self._features =[] self._features =[]
if ns == None:
self.ns = config.NS
else:
self.ns = ns
def features(self): def features(self):
""" return a list of features """ """ iterate over features """
return self._features for feature in self._features:
if isinstance(feature, (Folder, Placemark)):
yield feature
else:
raise TypeError(
"Features must be instances of (Folder, Placemark)")
def etree_element(self): def etree_element(self):
element = super(_Container, self).etree_element() element = super(_Container, self).etree_element()
......
...@@ -9,14 +9,10 @@ import logging ...@@ -9,14 +9,10 @@ import logging
logger = logging.getLogger('fastkml.styles') logger = logging.getLogger('fastkml.styles')
import config import config
from config import etree
from base import _BaseObject from base import _BaseObject
try:
from lxml import etree
LXML = True
except ImportError:
import xml.etree.ElementTree as etree
LXML = False
class StyleUrl(_BaseObject): class StyleUrl(_BaseObject):
...@@ -25,32 +21,25 @@ class StyleUrl(_BaseObject): ...@@ -25,32 +21,25 @@ class StyleUrl(_BaseObject):
is in the same file, use a # reference. If the style is defined in is in the same file, use a # reference. If the style is defined in
an external file, use a full URL along with # referencing. an external file, use a full URL along with # referencing.
""" """
__name__ = 'styleUrl'
url = None url = None
def __init__(self, ns=None, url=None): def __init__(self, ns=None, id=None, url=None):
super(StyleUrl, self).__init__(ns, id)
self.url = url self.url = url
if ns == None:
self.ns = config.NS
else:
self.ns = ns
def etree_element(self): def etree_element(self):
if self.url: if self.url:
element = etree.Element(self.ns + "styleUrl") element = super(StyleUrl, self).etree_element()
element.text = self.url element.text = self.url
return element return element
else: else:
logger.critical('No url given for styleUrl') logger.critical('No url given for styleUrl')
raise ValueError raise ValueError
def from_element(self, element): def from_element(self, element):
if self.ns + "styleUrl" != element.tag: super(StyleUrl, self).from_element(element)
raise TypeError self.url = element.text
else:
self.url = element.text
class _StyleSelector(_BaseObject): class _StyleSelector(_BaseObject):
...@@ -62,19 +51,6 @@ class _StyleSelector(_BaseObject): ...@@ -62,19 +51,6 @@ class _StyleSelector(_BaseObject):
by its id and its url. by its id and its url.
""" """
def etree_element(self):
element = etree.Element(self.ns + self.__name__)
if self.id:
element.set('id', self.id)
return element
def from_element(self, element):
if self.ns + self.__name__ != element.tag:
raise TypeError
else:
if element.get('id'):
self.id = element.get('id')
class Style(_StyleSelector): class Style(_StyleSelector):
""" """
...@@ -179,7 +155,6 @@ class StyleMap(_StyleSelector): ...@@ -179,7 +155,6 @@ class StyleMap(_StyleSelector):
normal = StyleUrl(self.ns) normal = StyleUrl(self.ns)
normal.from_element(style_url) normal.from_element(style_url)
else: else:
import ipdb; ipdb.set_trace()
raise ValueError raise ValueError
self.normal = normal self.normal = normal
else: else:
...@@ -226,19 +201,13 @@ class _ColorStyle(_BaseObject): ...@@ -226,19 +201,13 @@ class _ColorStyle(_BaseObject):
# A value of random applies a random linear scale to the base <color> # A value of random applies a random linear scale to the base <color>
def __init__(self, ns=None, id=None, color=None, colorMode=None): def __init__(self, ns=None, id=None, color=None, colorMode=None):
self.id = id super(_ColorStyle, self).__init__(ns, id)
if ns == None:
self.ns = config.NS
else:
self.ns = ns
self.color = color self.color = color
self.colorMode = colorMode self.colorMode = colorMode
def etree_element(self): def etree_element(self):
element = etree.Element(self.ns + self.__name__) element = super(_ColorStyle, self).etree_element()
if self.id:
element.set('id', self.id)
if self.color: if self.color:
color = etree.SubElement(element, "%scolor" %self.ns) color = etree.SubElement(element, "%scolor" %self.ns)
color.text = self.color color.text = self.color
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment