Package sld
[hide private]
[frames] | no frames]

Source Code for Package sld

   1  """ 
   2  StyledLayerDescriptor library for generating SLD documents. 
   3   
   4  SLD documents are used to style cartographic representations of geometric 
   5  features in most professional and desktop GIS applications. 
   6   
   7  Specification 
   8  ============= 
   9  The SLD specification is available from the Open Geospatial Consortium, 
  10  at U{http://www.opengeospatial.org/standards/sld} 
  11   
  12  License 
  13  ======= 
  14  Copyright 2011-2014 David Zwarg <U{david.a@zwarg.com}> 
  15   
  16  Licensed under the Apache License, Version 2.0 (the "License"); 
  17  you may not use this file except in compliance with the License. 
  18  You may obtain a copy of the License at 
  19   
  20  U{http://www.apache.org/licenses/LICENSE-2.0} 
  21   
  22  Unless required by applicable law or agreed to in writing, software 
  23  distributed under the License is distributed on an "AS IS" BASIS, 
  24  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  25  See the License for the specific language governing permissions and 
  26  limitations under the License. 
  27   
  28  @author: David Zwarg 
  29  @contact: david.a@zwarg.com 
  30  @copyright: 2011-2014, Azavea 
  31  @license: Apache 2.0 
  32  @version: 1.0.10 
  33  @newfield prop: Property, Properties 
  34  """ 
  35  from lxml.etree import parse, Element, XMLSchema, tostring 
  36  try: 
  37      from urllib2 import urlopen 
  38  except ImportError: 
  39      from urllib.request import urlopen 
  40  from tempfile import NamedTemporaryFile 
  41  import os 
  42  import copy 
  43  import logging 
44 45 46 -class SLDNode(object):
47 """ 48 A base class for all python objects that relate directly to SLD elements. 49 An SLDNode contains references to the underlying parent node, underlying 50 element node, and the namespace map. 51 52 The SLDNode base class also contains utility methods to construct properties 53 for child SLDNode objects. 54 """ 55 56 _nsmap = { 57 'sld': "http://www.opengis.net/sld", 58 'ogc': "http://www.opengis.net/ogc", 59 'xlink': "http://www.w3.org/1999/xlink", 60 'xsi': "http://www.w3.org/2001/XMLSchema-instance" 61 } 62 """Defined namespaces in SLD documents.""" 63
64 - def __init__(self, parent, descendant=True):
65 """ 66 Create a new SLDNode. It is not necessary to call this directly, because 67 all child classes should initialize the SLDNode internally. 68 69 @type parent: L{SLDNode} 70 @param parent: The parent class object. 71 @type descendant: boolean 72 @param descendant: Does this element descend from the parent, or is it a sibling? 73 """ 74 if parent is None: 75 self._parent = None 76 elif descendant: 77 self._parent = parent._node 78 else: 79 self._parent = parent._parent 80 self._node = None
81 82 @staticmethod
83 - def makeproperty(ns, cls=None, name=None, docstring='', descendant=True):
84 """ 85 Make a property on an instance of an SLDNode. If cls is omitted, the 86 property is assumed to be a text node, with no corresponding class 87 object. If name is omitted, the property is assumed to be a complex 88 node, with a corresponding class wrapper. 89 90 @type ns: string 91 @param ns: The namespace of this property's node. 92 @type cls: class 93 @param cls: Optional. The class of the child property. 94 @type name: string 95 @param name: Optional. The name of the child property. 96 @type docstring: string 97 @param docstring: Optional. The docstring to attach to the new property. 98 @type descendant: boolean 99 @param descendant: Does this element descend from the parent, or is it a sibling? 100 101 @rtype: property attribute 102 @return: A property attribute for this named property. 103 """ 104 def get_property(self): 105 """ 106 A generic property getter. 107 """ 108 if cls is None: 109 xpath = '%s:%s' % (ns, name) 110 else: 111 xpath = '%s:%s' % (ns, cls.__name__) 112 113 xpath = self._node.xpath(xpath, namespaces=SLDNode._nsmap) 114 if len(xpath) == 1: 115 if cls is None: 116 return xpath[0].text 117 else: 118 elem = cls.__new__(cls) 119 cls.__init__(elem, self, descendant=descendant) 120 return elem 121 else: 122 return None
123 124 def set_property(self, value): 125 """ 126 A generic property setter. 127 """ 128 if cls is None: 129 xpath = '%s:%s' % (ns, name) 130 else: 131 xpath = '%s:%s' % (ns, cls.__name__) 132 133 xpath = self._node.xpath(xpath, namespaces=SLDNode._nsmap) 134 if len(xpath) == 1: 135 if cls is None: 136 xpath[0].text = value 137 else: 138 xpath[0] = value._node 139 else: 140 if cls is None: 141 elem = self._node.makeelement('{%s}%s' % (SLDNode._nsmap[ns], name), nsmap=SLDNode._nsmap) 142 elem.text = value 143 self._node.append(elem) 144 else: 145 self._node.append(value._node)
146 147 def del_property(self): 148 """ 149 A generic property deleter. 150 """ 151 if cls is None: 152 xpath = '%s:%s' % (ns, name) 153 else: 154 xpath = '%s:%s' % (ns, cls.__name__) 155 156 xpath = self._node.xpath(xpath, namespaces=SLDNode._nsmap) 157 if len(xpath) == 1: 158 self._node.remove(xpath[0]) 159 160 return property(get_property, set_property, del_property, docstring) 161
162 - def get_or_create_element(self, ns, name):
163 """ 164 Attempt to get the only child element from this SLDNode. If the node 165 does not exist, create the element, attach it to the DOM, and return 166 the class object that wraps the node. 167 168 @type ns: string 169 @param ns: The namespace of the new element. 170 @type name: string 171 @param name: The name of the new element. 172 @rtype: L{SLDNode} 173 @return: The wrapped node, in the parent's property class. This will 174 always be a descendent of SLDNode. 175 """ 176 if len(self._node.xpath('%s:%s' % (ns, name), namespaces=SLDNode._nsmap)) == 1: 177 return getattr(self, name) 178 179 return self.create_element(ns, name)
180
181 - def create_element(self, ns, name):
182 """ 183 Create an element as a child of this SLDNode. 184 185 @type ns: string 186 @param ns: The namespace of the new element. 187 @type name: string 188 @param name: The name of the new element. 189 @rtype: L{SLDNode} 190 @return: The wrapped node, in the parent's property class. This will 191 always be a descendent of SLDNode. 192 """ 193 elem = self._node.makeelement('{%s}%s' % (SLDNode._nsmap[ns], name), nsmap=SLDNode._nsmap) 194 self._node.append(elem) 195 196 return getattr(self, name)
197
198 199 -class CssParameter(SLDNode):
200 """ 201 A css styling parameter. May be a child of L{Fill}, L{Font}, and L{Stroke}. 202 """
203 - def __init__(self, parent, index, descendant=True):
204 """ 205 Create a new CssParameter from an existing StyleItem. 206 207 @type parent: L{StyleItem} 208 @param parent: The parent class object. 209 @type index: integer 210 @param index: The index of the node in the list of all CssParameters in the parent. 211 @type descendant: boolean 212 @param descendant: Does this element descend from the parent, or is it a sibling? 213 """ 214 super(CssParameter, self).__init__(parent, descendant=descendant) 215 self._node = self._parent.xpath('sld:CssParameter', namespaces=SLDNode._nsmap)[index]
216
217 - def get_name(self):
218 """ 219 Get the name attribute. 220 221 @rtype: string 222 @return: The value of the 'name' attribute. 223 """ 224 return self._node.attrib['name']
225
226 - def set_name(self, value):
227 """ 228 Set the name attribute. 229 230 @type value: string 231 @param value: The value of the 'name' attribute. 232 """ 233 self._node.attrib['name'] = value
234
235 - def del_name(self):
236 """ 237 Delete the name attribute. 238 """ 239 del self._node.attrib['name']
240 241 Name = property(get_name, set_name, del_name, "The value of the 'name' attribute.") 242 """The value of the 'name' attribute.""" 243
244 - def get_value(self):
245 """ 246 Get the text content. 247 248 @rtype: string 249 @return: The text content. 250 """ 251 return self._node.text
252
253 - def set_value(self, value):
254 """ 255 Set the text content. 256 257 @type value: string 258 @param value: The text content. 259 """ 260 self._node.text = value
261
262 - def del_value(self):
263 """ 264 Delete the text content. 265 """ 266 self._node.clear()
267 268 Value = property(get_value, set_value, del_value, "The value of the parameter.") 269 """The value of the parameter."""
270
271 272 -class CssParameters(SLDNode):
273 """ 274 A collection of L{CssParameter} nodes. This is a pythonic helper (list of 275 nodes) that does not correspond to a true element in the SLD spec. 276 """
277 - def __init__(self, parent):
278 """ 279 Create a new list of CssParameters from the specified parent node. 280 281 @type parent: L{StyleItem} 282 @param parent: The parent class item. 283 """ 284 super(CssParameters, self).__init__(parent) 285 self._node = None 286 self._nodes = self._parent.xpath('sld:CssParameter', namespaces=SLDNode._nsmap)
287
288 - def __len__(self):
289 """ 290 Get the number of L{CssParameter} nodes in this list. 291 292 @rtype: integer 293 @return: The number of L{CssParameter} nodes. 294 """ 295 return len(self._nodes)
296
297 - def __getitem__(self, key):
298 """ 299 Get one of the L{CssParameter} nodes in the list. 300 301 @type key: integer 302 @param key: The index of the child node. 303 @rtype: L{CssParameter} 304 @return: The specific L{CssParameter} node. 305 """ 306 return CssParameter(self, key, descendant=False)
307
308 - def __setitem__(self, key, value):
309 """ 310 Set one of the L{CssParameter} nodes in the list with a new value. 311 312 @type key: integer 313 @param key: The index of the child node. 314 @type value: L{CssParameter}, etree.Element 315 @param value: The new value of the specific child node. 316 """ 317 if isinstance(value, CssParameter): 318 self._nodes.replace(self._nodes[key], value._node) 319 elif isinstance(value, Element): 320 self._nodes.replace(self._nodes[key], value)
321
322 - def __delitem__(self, key):
323 """ 324 Delete one of the L{CssParameter} nodes from the list. 325 326 @type key: integer 327 @param key: The index of the child node. 328 """ 329 self._nodes.remove(self._nodes[key])
330
331 332 -class StyleItem(SLDNode):
333 """ 334 Abstract base class for all nodes that contain a list of L{CssParameter} nodes. 335 """
336 - def __init__(self, parent, name, descendant=True):
337 """ 338 Create a new StyleItem. 339 340 @type parent: L{Symbolizer} 341 @param parent: The parent class object. 342 @type name: string 343 @param name: The name of the node. 344 @type descendant: boolean 345 @param descendant: Does this element descend from the parent, or is it a sibling? 346 """ 347 super(StyleItem, self).__init__(parent, descendant=descendant) 348 xpath = self._parent.xpath('sld:' + name, namespaces=SLDNode._nsmap) 349 if len(xpath) < 1: 350 self._node = self._parent.makeelement('{%s}%s' % (SLDNode._nsmap['sld'], name), nsmap=SLDNode._nsmap) 351 self._parent.append(self._node) 352 else: 353 self._node = xpath[0]
354 355 @property
356 - def CssParameters(self):
357 """ 358 Get the list of L{CssParameter} nodes in a friendly L{CssParameters} helper list. 359 360 @rtype: L{CssParameters} 361 @return: A pythonic list of L{CssParameter} children. 362 """ 363 return CssParameters(self)
364
365 - def create_cssparameter(self, name=None, value=None):
366 """ 367 Create a new L{CssParameter} node as a child of this element, and attach it to the DOM. 368 Optionally set the name and value of the parameter, if they are both provided. 369 370 @type name: string 371 @param name: Optional. The name of the L{CssParameter} 372 @type value: string 373 @param value: Optional. The value of the L{CssParameter} 374 @rtype: L{CssParameter} 375 @return: A new style parameter, set to the name and value. 376 """ 377 elem = self._node.makeelement('{%s}CssParameter' % SLDNode._nsmap['sld'], nsmap=SLDNode._nsmap) 378 self._node.append(elem) 379 380 if not (name is None or value is None): 381 elem.attrib['name'] = name 382 elem.text = value 383 384 return CssParameter(self, len(self._node) - 1)
385
386 387 -class Fill(StyleItem):
388 """ 389 A style specification for fill types. This class contains a 390 L{CssParameters} list, which can include: 391 392 - fill 393 - fill-opacity 394 395 This class is a property of any L{Symbolizer}. 396 """
397 - def __init__(self, parent, descendant=True):
398 """ 399 Create a new Fill node from the specified parent. 400 401 @type parent: L{Symbolizer} 402 @param parent: The parent class object. 403 @type descendant: boolean 404 @param descendant: A flag indicating if this is a descendant node of the parent. 405 """ 406 super(Fill, self).__init__(parent, 'Fill', descendant=descendant)
407
408 409 -class Font(StyleItem):
410 """ 411 A style specification for font types. This class contains a 412 L{CssParameters} list, which can include: 413 414 - font-family 415 - font-size 416 - font-style 417 - font-weight 418 419 This class is a property of any L{Symbolizer}. 420 """
421 - def __init__(self, parent, descendant=True):
422 """ 423 Create a new Font node from the specified parent. 424 425 @type parent: L{Symbolizer} 426 @param parent: The parent class object. 427 @type descendant: boolean 428 @param descendant: A flag indicating if this is a descendant node of the parent. 429 """ 430 super(Font, self).__init__(parent, 'Font', descendant=descendant)
431
432 433 -class Stroke(StyleItem):
434 """ 435 A style specification for stroke types. This class contains a 436 L{CssParameters} list, which can include: 437 438 - stroke 439 - stroke-dasharray 440 - stroke-dashoffset 441 - stroke-linecap 442 - stroke-linejoin 443 - stroke-opacity 444 - stroke-width 445 446 This class is a property of any L{Symbolizer}. 447 """
448 - def __init__(self, parent, descendant=True):
449 """ 450 Create a new Stroke node from the specified parent. 451 452 @type parent: L{Symbolizer} 453 @param parent: The parent class object. 454 @type descendant: boolean 455 @param descendant: A flag indicating if this is a descendant node of the parent. 456 """ 457 super(Stroke, self).__init__(parent, 'Stroke', descendant=descendant)
458
459 460 -class Symbolizer(SLDNode):
461 """ 462 Abstract base class for all symbolizer nodes. Symbolizer nodes are those 463 that contain L{Fill}, L{Font}, or L{Stroke} children. 464 465 All derived Symbolizer classes have access to the Fill, Font, and Stroke properties. 466 467 @prop: B{Fill} 468 469 The element that contains the L{CssParameter} nodes for describing the polygon fill styles. 470 471 I{Type}: L{Fill} 472 473 @prop: B{Font} 474 475 The element that contains the L{CssParameter} nodes for describing the font styles. 476 477 I{Type}: L{Font} 478 479 @prop: B{Stroke} 480 481 The element that contains the L{CssParameter} nodes for describing the line styles. 482 483 I{Type}: L{Stroke} 484 """
485 - def __init__(self, parent, name, descendant=True):
486 """ 487 Create a new Symbolizer node. If the specified node is not found in the 488 DOM, the node will be created and attached to the parent. 489 490 @type parent: L{Rule} 491 @param parent: The parent class object. 492 @type name: string 493 @param name: The type of symbolizer node. If this parameter ends with 494 the character '*', the '*' will get expanded into 'Symbolizer'. 495 @type descendant: boolean 496 @param descendant: A flag indicating if this is a descendant node of the parent. 497 """ 498 super(Symbolizer, self).__init__(parent, descendant=descendant) 499 500 if name[len(name) - 1] == '*': 501 name = name[0:-1] + 'Symbolizer' 502 503 xpath = self._parent.xpath('sld:%s' % name, namespaces=SLDNode._nsmap) 504 if len(xpath) < 1: 505 self._node = self._parent.makeelement('{%s}%s' % (SLDNode._nsmap['sld'], name), nsmap=SLDNode._nsmap) 506 self._parent.append(self._node) 507 else: 508 self._node = xpath[0] 509 510 setattr(self.__class__, 'Fill', SLDNode.makeproperty('sld', cls=Fill, 511 docstring="The parameters for describing the fill styling.")) 512 setattr(self.__class__, 'Font', SLDNode.makeproperty('sld', cls=Font, 513 docstring="The parameters for describing the font styling.")) 514 setattr(self.__class__, 'Stroke', SLDNode.makeproperty('sld', cls=Stroke, 515 docstring="The parameters for describing the stroke styling."))
516
517 - def create_fill(self):
518 """ 519 Create a new L{Fill} element on this Symbolizer. 520 521 @rtype: L{Fill} 522 @return: A new fill element, attached to this symbolizer. 523 """ 524 return self.create_element('sld', 'Fill')
525
526 - def create_font(self):
527 """ 528 Create a new L{Font} element on this Symbolizer. 529 530 @rtype: L{Font} 531 @return: A new font element, attached to this symbolizer. 532 """ 533 return self.create_element('sld', 'Font')
534
535 - def create_stroke(self):
536 """ 537 Create a new L{Stroke} element on this Symbolizer. 538 539 @rtype: L{Stroke} 540 @return: A new stroke element, attached to this symbolizer. 541 """ 542 return self.create_element('sld', 'Stroke')
543
544 545 -class PolygonSymbolizer(Symbolizer):
546 """ 547 A symbolizer for polygon geometries. A PolygonSymbolizer is a child of a 548 L{Rule} element. 549 550 @prop: Fill 551 552 The element that contains the L{CssParameter} nodes for describing the 553 polygon fill styles. 554 555 I{Type}: L{Fill} 556 557 @prop: Stroke 558 559 The element that contains the L{CssParameter} nodes for describing the line 560 styles. 561 562 I{Type}: L{Stroke} 563 """
564 - def __init__(self, parent, descendant=True):
565 """ 566 Create a new PolygonSymbolizer node, as a child of the specified parent. 567 568 @type parent: L{Rule} 569 @param parent: The parent class object. 570 @type descendant: boolean 571 @param descendant: A flag indicating if this is a descendant node of the parent. 572 """ 573 super(PolygonSymbolizer, self).__init__(parent, 'Polygon*', descendant)
574
575 576 -class LineSymbolizer(Symbolizer):
577 """ 578 A symbolizer for line geometries. A LineSymbolizer is a child of a 579 L{Rule} element. 580 581 @prop: Stroke 582 583 The element that contains the L{CssParameter} nodes for describing the line 584 styles. 585 586 I{Type}: L{Stroke} 587 """
588 - def __init__(self, parent, descendant=True):
589 """ 590 Create a new LineSymbolizer node, as a child of the specified parent. 591 592 @type parent: L{Rule} 593 @param parent: The parent class object. 594 @type descendant: boolean 595 @param descendant: A flag indicating if this is a descendant node of the parent. 596 """ 597 super(LineSymbolizer, self).__init__(parent, 'Line*', descendant)
598
599 600 -class TextSymbolizer(Symbolizer):
601 """ 602 A symbolizer for text labels. A TextSymbolizer is a child of a L{Rule} 603 element. 604 605 @prop: Fill 606 607 The element that contains the L{CssParameter} nodes for describing the 608 character fill styles. 609 610 I{Type}: L{Fill} 611 """
612 - def __init__(self, parent, descendant=True):
613 """ 614 Create a new TextSymbolizer node, as a child of the specified parent. 615 616 @type parent: L{Rule} 617 @param parent: The parent class object. 618 @type descendant: boolean 619 @param descendant: A flag indicating if this is a descendant node of the parent. 620 """ 621 super(TextSymbolizer, self).__init__(parent, 'Text*', descendant=descendant)
622
623 624 -class Mark(Symbolizer):
625 """ 626 A graphic mark for describing points. A Mark is a child of a L{Graphic} 627 element. 628 629 @prop: Fill 630 631 The element that contains the L{CssParameter} nodes for describing the 632 fill styles. 633 634 I{Type}: L{Fill} 635 636 @prop: Stroke 637 638 The element that contains the L{CssParameter} nodes for describing the 639 line styles. 640 641 I{Type}: L{Stroke} 642 643 @prop: WellKnownName 644 645 A string describing the Mark, which may be one of: 646 - circle 647 - cross 648 - square 649 - star 650 - triangle 651 - x 652 653 I{Type}: string 654 """
655 - def __init__(self, parent, descendant=True):
656 """ 657 Create a new Mark node, as a child of the specified parent. 658 659 @type parent: L{Graphic} 660 @param parent: The parent class object. 661 @type descendant: boolean 662 @param descendant: A flag indicating if this is a descendant node of the parent. 663 """ 664 super(Mark, self).__init__(parent, 'Mark', descendant=descendant) 665 666 setattr(self.__class__, 'WellKnownName', SLDNode.makeproperty('sld', name='WellKnownName', 667 docstring="The well known name for the mark."))
668
669 670 -class Graphic(SLDNode):
671 """ 672 A Graphic node represents a graphical mark for representing points. A 673 Graphic is a child of a L{PointSymbolizer} element. 674 675 @prop: Mark 676 677 The element that contains the L{CssParameter} nodes for describing the point styles. 678 679 I{Type}: L{Mark} 680 681 @prop: Opacity 682 683 Bewteen 0 (completely transparent) and 1 (completely opaque) 684 685 I{Type}: float 686 687 @prop: Size 688 689 The size of the graphic, in pixels. 690 691 I{Type}: integer 692 693 @prop: Rotation 694 695 Clockwise degrees of rotation. 696 697 I{Type}: float 698 """
699 - def __init__(self, parent, descendant=True):
700 """ 701 Create a new Graphic node, as a child of the specified parent. 702 703 @type parent: L{PointSymbolizer} 704 @param parent: The parent class object. 705 @type descendant: boolean 706 @param descendant: A flag indicating if this is a descendant node of the parent. 707 """ 708 super(Graphic, self).__init__(parent, descendant=descendant) 709 xpath = self._parent.xpath('sld:Graphic', namespaces=SLDNode._nsmap) 710 if len(xpath) < 1: 711 self._node = self._parent.makeelement('{%s}Graphic' % SLDNode._nsmap['sld'], nsmap=SLDNode._nsmap) 712 self._parent.append(self._node) 713 else: 714 self._node = xpath[0] 715 716 setattr(self.__class__, 'Mark', SLDNode.makeproperty('sld', cls=Mark, 717 docstring="The graphic's mark styling.")) 718 setattr(self.__class__, 'Opacity', SLDNode.makeproperty('sld', name='Opacity', 719 docstring="The opacity of the graphic.")) 720 setattr(self.__class__, 'Size', SLDNode.makeproperty('sld', name='Size', 721 docstring="The size of the graphic, in pixels.")) 722 setattr(self.__class__, 'Rotation', SLDNode.makeproperty('sld', name='Rotation', 723 docstring="The rotation of the graphic, in degrees clockwise."))
724
725 726 -class PointSymbolizer(SLDNode):
727 """ 728 A symbolizer for point geometries. A PointSymbolizer is a child of a 729 L{Rule} element. 730 731 @prop: Graphic 732 733 The configuration of the point graphic. 734 735 I{Type}: L{Graphic} 736 """
737 - def __init__(self, parent, descendant=True):
738 """ 739 Create a new PointSymbolizer node, as a child of the specified parent. 740 741 @type parent: L{Rule} 742 @param parent: The parent class object. 743 @type descendant: boolean 744 @param descendant: A flag indicating if this is a descendant node of the parent. 745 """ 746 super(PointSymbolizer, self).__init__(parent, descendant=descendant) 747 xpath = self._parent.xpath('sld:PointSymbolizer', namespaces=SLDNode._nsmap) 748 if len(xpath) < 1: 749 self._node = self._parent.makeelement('{%s}PointSymbolizer' % SLDNode._nsmap['sld'], nsmap=SLDNode._nsmap) 750 self._parent.append(self._node) 751 else: 752 self._node = xpath[0] 753 754 setattr(self.__class__, 'Graphic', SLDNode.makeproperty('sld', cls=Graphic, 755 docstring="The graphic settings for this point geometry."))
756
757 758 -class PropertyCriterion(SLDNode):
759 """ 760 General property criterion class for all property comparitors. 761 A PropertyCriterion is a child of a L{Filter} element. 762 763 Valid property comparitors that are represented by this class are: 764 765 - PropertyIsNotEqual 766 - PropertyIsLessThan 767 - PropertyIsLessThanOrEqual 768 - PropertyIsEqual 769 - PropertyIsGreaterThan 770 - PropertyIsGreaterThanOrEqual 771 - PropertyIsLike 772 773 @prop: PropertyName 774 775 The name of the property to use in the comparison. 776 777 I{Type}: string 778 779 @prop: Literal 780 781 The value of the property. 782 783 I{Type}: string 784 """
785 - def __init__(self, parent, name, descendant=True):
786 """ 787 Create a new PropertyCriterion node, as a child of the specified parent. 788 A PropertyCriterion is not represented in the SLD Spec. This class 789 is a generalization of many of the PropertyIs... elements present in 790 the OGC Filter spec. 791 792 @type parent: L{Filter} 793 @param parent: The parent class object. 794 """ 795 super(PropertyCriterion, self).__init__(parent, descendant=descendant) 796 xpath = self._parent.xpath('ogc:' + name, namespaces=SLDNode._nsmap) 797 if len(xpath) < 1: 798 self._node = self._parent.makeelement('{%s}%s' % (SLDNode._nsmap['ogc'], name), nsmap=SLDNode._nsmap) 799 self._parent.append(self._node) 800 else: 801 self._node = xpath[0] 802 803 setattr(self.__class__, 'PropertyName', SLDNode.makeproperty('ogc', name='PropertyName', 804 docstring="The name of the property to compare.")) 805 setattr(self.__class__, 'Literal', SLDNode.makeproperty('ogc', name='Literal', 806 docstring="The literal value of the property to compare against."))
807
808 809 -class Filter(SLDNode):
810 """ 811 A filter object that stores the property comparitors. A Filter is a child 812 of a L{Rule} element. Filter nodes are pythonic, and have some syntactic 813 sugar that allows the creation of simple logical combinations. 814 815 To create an AND logical filter, use the '+' operator: 816 817 >>> rule.Filter = filter1 + filter2 818 819 To create an OR logical filter, use the '|' operator: 820 821 >>> rule.Filter = filter1 | filter2 822 823 Complex combinations can be created by chaining these operations together: 824 825 >>> rule.Filter = filter1 | (filter2 + filter3) 826 827 @prop: PropertyIsEqualTo 828 829 A specification of property (=) equality. 830 831 I{Type}: L{PropertyCriterion} 832 833 @prop: PropertyIsNotEqualTo 834 835 A specification of property (!=) inequality. 836 837 I{Type}: L{PropertyCriterion} 838 839 @prop: PropertyIsLessThan 840 841 A specification of property less-than (<) comparison. 842 843 I{Type}: L{PropertyCriterion} 844 845 @prop: PropertyIsLessThanOrEqualTo 846 847 A specification of property less-than-or-equal-to (<=) comparison. 848 849 I{Type}: L{PropertyCriterion} 850 851 @prop: PropertyIsGreaterThan 852 853 A specification of property greater-than (>) comparison, 854 855 I{Type}: L{PropertyCriterion} 856 857 @prop: PropertyIsGreaterThanOrEqualTo 858 859 A specification of property greater-than-or-equal-to (>=) comparison. 860 861 I{Type}: L{PropertyCriterion} 862 """
863 - def __init__(self, parent, descendant=True):
864 """ 865 Create a new Filter node. 866 867 @type parent: L{Rule} 868 @param parent: The parent class object. 869 @type descendant: boolean 870 @param descendant: A flag indicating if this is a descendant node of the parent. 871 """ 872 super(Filter, self).__init__(parent, descendant=descendant) 873 xpath = self._parent.xpath('ogc:Filter', namespaces=SLDNode._nsmap) 874 if len(xpath) == 1: 875 self._node = xpath[0] 876 else: 877 self._node = self._parent.makeelement('{%s}Filter' % SLDNode._nsmap['ogc'], nsmap=SLDNode._nsmap)
878
879 - def __add__(self, other):
880 """ 881 Add two filters together to create one AND logical filter. 882 883 @type other: L{Filter} 884 @param other: A filter to AND with this one. 885 @rtype: L{Filter} 886 @return: A new filter with an ogc:And element as its child. 887 """ 888 if not self._node.getparent() is None: 889 self._node.getparent().remove(self._node) 890 elem = self._node.makeelement('{%s}And' % SLDNode._nsmap['ogc']) 891 elem.append(copy.copy(self._node[0])) 892 elem.append(copy.copy(other._node[0])) 893 894 f = Filter(self) 895 f._node.append(elem) 896 897 return f
898
899 - def __or__(self, other):
900 """ 901 Or two filters together to create on OR logical filter. 902 903 @type other: L{Filter} 904 @param other: A filter to OR with this one. 905 @rtype: L{Filter} 906 @return: A new filter with an ogc:Or element as its child. 907 """ 908 elem = self._node.makeelement('{%s}Or' % SLDNode._nsmap['ogc']) 909 elem.append(copy.copy(self._node[0])) 910 elem.append(copy.copy(other._node[0])) 911 912 f = Filter(self) 913 f._node.append(elem) 914 915 return f
916
917 - def __getattr__(self, name):
918 """ 919 Get a named attribute from this Filter instance. This method allows 920 properties with the prefix of 'PropertyIs' to be set, and raises 921 an AttributeError for all other property names. 922 923 @type name: string 924 @param name: The name of the property. 925 @rtype: L{PropertyCriterion} 926 @return: The property comparitor. 927 """ 928 if not name.startswith('PropertyIs'): 929 raise AttributeError('Property name must be one of: PropertyIsEqualTo, PropertyIsNotEqualTo, PropertyIsLessThan, PropertyIsLessThanOrEqualTo, PropertyIsGreaterThan, PropertyIsGreaterThanOrEqualTo, PropertyIsLike.') 930 xpath = self._node.xpath('ogc:' + name, namespaces=SLDNode._nsmap) 931 if len(xpath) == 0: 932 return None 933 934 return PropertyCriterion(self, name)
935
936 - def __setattr__(self, name, value):
937 """ 938 Set a named attribute on this Filter instance. If the property name 939 begins with 'PropertyIs', the node value will be appended to the filter. 940 941 @type name: string 942 @param name: The name of the property. 943 @type value: L{PropertyCriterion} 944 @param value: The new property comparitor. 945 """ 946 if not name.startswith('PropertyIs'): 947 object.__setattr__(self, name, value) 948 return 949 950 xpath = self._node.xpath('ogc:' + name, namespaces=SLDNode._nsmap) 951 if len(xpath) > 0: 952 xpath[0] = value 953 else: 954 elem = self._node.makeelement('{%s}%s' % (SLDNode._nsmap['ogc'], name), nsmap=SLDNode._nsmap) 955 self._node.append(elem)
956
957 - def __delattr__(self, name):
958 """ 959 Delete the property from the Filter. This removes the child node 960 of this name from the Filter. 961 962 @type name: string 963 @param name: The name of the property. 964 """ 965 xpath = self._node.xpath('ogc:' + name, namespaces=SLDNode._nsmap) 966 if len(xpath) > 0: 967 self._node.remove(xpath[0])
968
969 970 -class Rule(SLDNode):
971 """ 972 A rule object contains a title, an optional L{Filter}, and one or more 973 L{Symbolizer}s. A Rule is a child of a L{FeatureTypeStyle}. 974 975 @prop: Title 976 977 The title of this rule. This is required for a valid SLD. 978 979 I{Type}: string 980 981 @prop: Filter 982 983 Optional. A filter defines logical comparisons against properties. 984 985 I{Type}: L{Filter} 986 987 @prop: MinScaleDenominator 988 989 The minimum scale (inclusive) at which this rule should be applied. 990 991 I{Type}: string 992 993 @prop: MaxScaleDenominator 994 995 The maximum scale (exclusive) at which this rule should be applied. 996 997 I{Type}: string 998 999 @prop: PolygonSymbolizer 1000 1001 A symbolizer that defines how polygons should be rendered. 1002 1003 I{Type}: L{PolygonSymbolizer} 1004 1005 @prop: LineSymbolizer 1006 1007 A symbolizer that defines how lines should be rendered. 1008 1009 I{Type}: L{LineSymbolizer} 1010 1011 @prop: TextSymbolizer 1012 1013 A symbolizer that defines how text should be rendered. 1014 1015 I{Type}: L{TextSymbolizer} 1016 1017 @prop: PointSymbolizer 1018 1019 A symbolizer that defines how points should be rendered. 1020 1021 I{Type}: L{PointSymbolizer} 1022 """
1023 - def __init__(self, parent, index, descendant=True):
1024 """ 1025 Create a new Rule node. 1026 1027 @type parent: L{FeatureTypeStyle} 1028 @param parent: The parent class object. 1029 @type descendant: boolean 1030 @param descendant: A flag indicating if this is a descendant node of the parent. 1031 """ 1032 super(Rule, self).__init__(parent, descendant=descendant) 1033 self._node = self._parent.xpath('sld:Rule', namespaces=SLDNode._nsmap)[index] 1034 1035 setattr(self.__class__, 'Title', SLDNode.makeproperty('sld', name='Title', 1036 docstring="The title of the Rule.")) 1037 setattr(self.__class__, 'Filter', SLDNode.makeproperty('ogc', cls=Filter, 1038 docstring="The optional filter object, with property comparitors.")) 1039 setattr(self.__class__, 'PolygonSymbolizer', SLDNode.makeproperty('sld', cls=PolygonSymbolizer, 1040 docstring="The optional polygon symbolizer for this rule.")) 1041 setattr(self.__class__, 'LineSymbolizer', SLDNode.makeproperty('sld', cls=LineSymbolizer, 1042 docstring="The optional line symbolizer for this rule.")) 1043 setattr(self.__class__, 'TextSymbolizer', SLDNode.makeproperty('sld', cls=TextSymbolizer, 1044 docstring="The optional text symbolizer for this rule.")) 1045 setattr(self.__class__, 'PointSymbolizer', SLDNode.makeproperty('sld', cls=PointSymbolizer, 1046 docstring="The optional point symbolizer for this rule.")) 1047 setattr(self.__class__, 'MinScaleDenominator', SLDNode.makeproperty('sld', name='MinScaleDenominator', 1048 docstring="The minimum scale denominator for this rule.")) 1049 setattr(self.__class__, 'MaxScaleDenominator', SLDNode.makeproperty('sld', name='MaxScaleDenominator', 1050 docstring="The maximum scale denominator for this rule."))
1051
1052 - def normalize(self):
1053 """ 1054 Normalize this node prior to validation. This is required, as the 1055 ogc:Filter node must come before any symbolizer nodes. The SLD 1056 is modified in place. 1057 """ 1058 order = [ 1059 'sld:Title', 'ogc:Filter', 'sld:MinScaleDenominator', 1060 'sld:MaxScaleDenominator', 'sld:PolygonSymbolizer', 1061 'sld:LineSymbolizer', 'sld:TextSymbolizer', 'sld:PointSymbolizer'] 1062 for item in order: 1063 xpath = self._node.xpath(item, namespaces=SLDNode._nsmap) 1064 for xitem in xpath: 1065 # move this to the end 1066 self._node.remove(xitem) 1067 self._node.append(xitem)
1068 1069 # no need to normalize children 1070
1071 - def create_filter(self, propname=None, comparitor=None, value=None):
1072 """ 1073 Create a L{Filter} for this rule. The property name, comparitor, and value 1074 are required to create a valid Filter. 1075 1076 @type propname: string 1077 @param propname: The name of the property to filter. 1078 @type comparitor: string 1079 @param comparitor: The comparison to perform on the property. One of 1080 "!=", "<", "<=", "=", ">=", ">", and "%" is required. 1081 @type value: string 1082 @param value: The value of the property to compare against. 1083 @rtype: L{Filter} 1084 @return: A new filter attached to this Rule. 1085 """ 1086 if propname is None or comparitor is None or value is None: 1087 return None 1088 1089 rfilter = self.create_element('ogc', 'Filter') 1090 ftype = None 1091 if comparitor == '==': 1092 ftype = 'PropertyIsEqualTo' 1093 elif comparitor == '<=': 1094 ftype = 'PropertyIsLessThanOrEqualTo' 1095 elif comparitor == '<': 1096 ftype = 'PropertyIsLessThan' 1097 elif comparitor == '>=': 1098 ftype = 'PropertyIsGreaterThanOrEqualTo' 1099 elif comparitor == '>': 1100 ftype = 'PropertyIsGreaterThan' 1101 elif comparitor == '!=': 1102 ftype = 'PropertyIsNotEqualTo' 1103 elif comparitor == '%': 1104 ftype = 'PropertyIsLike' 1105 1106 if not ftype is None: 1107 prop = PropertyCriterion(rfilter, ftype) 1108 prop.PropertyName = propname 1109 if not value is None: 1110 prop.Literal = value 1111 setattr(rfilter, ftype, prop) 1112 1113 return rfilter
1114
1115 - def create_symbolizer(self, stype):
1116 """ 1117 Create a L{Symbolizer} of the specified type on this rule. 1118 1119 @type stype: string 1120 @param stype: The type of symbolizer. Allowed types are "Point", 1121 "Line", "Polygon", or "Text". 1122 @rtype: L{Symbolizer} 1123 @return: A newly created symbolizer, attached to this Rule. 1124 """ 1125 if stype is None: 1126 return None 1127 1128 return self.create_element('sld', stype + 'Symbolizer')
1129
1130 1131 -class Rules(SLDNode):
1132 """ 1133 A collection of L{Rule} nodes. This is a pythonic helper (list of 1134 nodes) that does not correspond to a true element in the SLD spec. 1135 """
1136 - def __init__(self, parent, descendant=True):
1137 """ 1138 Create a new list of Rules from the specified parent node. 1139 1140 @type parent: L{FeatureTypeStyle} 1141 @param parent: The parent class object. 1142 @type descendant: boolean 1143 @param descendant: A flag indicating if this is a descendant node of the parent. 1144 """ 1145 super(Rules, self).__init__(parent, descendant=descendant) 1146 self._node = None 1147 self._nodes = self._parent.xpath('sld:Rule', namespaces=SLDNode._nsmap)
1148
1149 - def normalize(self):
1150 """ 1151 Normalize this node and all rules contained within. The SLD model is 1152 modified in place. 1153 """ 1154 for i, rnode in enumerate(self._nodes): 1155 rule = Rule(self, i - 1, descendant=False) 1156 rule.normalize()
1157
1158 - def __len__(self):
1159 """ 1160 Get the number of L{CssParameter} nodes in this list. 1161 1162 @rtype: integer 1163 @return: The number of L{CssParameter} nodes. 1164 """ 1165 return len(self._nodes)
1166
1167 - def __getitem__(self, key):
1168 """ 1169 Get one of the L{Rule} nodes in the list. 1170 1171 @type key: integer 1172 @param key: The index of the child node. 1173 @rtype: L{Rule} 1174 @return: The specific L{Rule} node. 1175 """ 1176 rule = Rule(self, key, descendant=False) 1177 return rule
1178
1179 - def __setitem__(self, key, value):
1180 """ 1181 Set one of the L{Rule} nodes in the list with a new value. 1182 1183 @type key: integer 1184 @param key: The index of the child node. 1185 @type value: L{Rule}, etree.Element 1186 @param value: The new value of the specific child node. 1187 """ 1188 if isinstance(value, Rule): 1189 self._nodes.replace(self._nodes[key], value._node) 1190 elif isinstance(value, Element): 1191 self._nodes.replace(self._nodes[key], value)
1192
1193 - def __delitem__(self, key):
1194 """ 1195 Delete one of the L{Rule} nodes from the list. 1196 1197 @type key: integer 1198 @param key: The index of the child node. 1199 """ 1200 self._nodes.remove(self._nodes[key])
1201
1202 1203 -class FeatureTypeStyle(SLDNode):
1204 """ 1205 A FeatureTypeStyle node contains all L{Rule} objects applicable to a 1206 specific layer. A FeatureTypeStyle is a child of a L{UserStyle} element. 1207 """
1208 - def __init__(self, parent, descendant=True):
1209 """ 1210 Create a new FeatureTypeNode node, as a child of the specified parent. 1211 1212 @type parent: L{UserStyle} 1213 @param parent: The parent class object. 1214 @type descendant: boolean 1215 @param descendant: A flag indicating if this is a descendant node of the parent. 1216 """ 1217 super(FeatureTypeStyle, self).__init__(parent, descendant=descendant) 1218 self._node = self._parent.xpath('sld:FeatureTypeStyle', namespaces=SLDNode._nsmap)[0]
1219
1220 - def normalize(self):
1221 """ 1222 Normalize this element and all child L{Rule}s. The SLD model is 1223 modified in place. 1224 """ 1225 if not self.Rules is None: 1226 self.Rules.normalize()
1227 1228 @property
1229 - def Rules(self):
1230 """ 1231 Get the L{sld.Rules} pythonic list helper for all L{Rule} objects in this 1232 style. 1233 1234 @rtype: L{sld.Rules} 1235 @return: A list of all rules applied to this style. 1236 """ 1237 return Rules(self)
1238
1239 - def create_rule(self, title, symbolizer=None, MinScaleDenominator=None, MaxScaleDenominator=None):
1240 """ 1241 Create a L{Rule} object on this style. A rule requires a title and 1242 symbolizer. If no symbolizer is specified, a PointSymbolizer will be 1243 assigned to the rule. 1244 1245 @type title: string 1246 @param title: The name of the new L{Rule}. 1247 @type symbolizer: L{Symbolizer} I{class} 1248 @param symbolizer: The symbolizer type. This is the class object (as 1249 opposed to a class instance) of the symbolizer to use. 1250 @rtype: L{Rule} 1251 @return: A newly created rule, attached to this FeatureTypeStyle. 1252 """ 1253 elem = self._node.makeelement('{%s}Rule' % SLDNode._nsmap['sld'], nsmap=SLDNode._nsmap) 1254 self._node.append(elem) 1255 1256 rule = Rule(self, len(self._node) - 1) 1257 rule.Title = title 1258 1259 if MinScaleDenominator is not None: 1260 rule.MinScaleDenominator = MinScaleDenominator 1261 if MaxScaleDenominator is not None: 1262 rule.MaxScaleDenominator = MaxScaleDenominator 1263 1264 if symbolizer is None: 1265 symbolizer = PointSymbolizer 1266 1267 sym = symbolizer(rule) 1268 if symbolizer == PointSymbolizer: 1269 gph = Graphic(sym) 1270 mrk = Mark(gph) 1271 mrk.WellKnownName = 'square' 1272 fill = Fill(mrk) 1273 fill.create_cssparameter('fill', '#ff0000') 1274 1275 elif symbolizer == LineSymbolizer: 1276 stroke = Stroke(sym) 1277 stroke.create_cssparameter('stroke', '#0000ff') 1278 1279 elif symbolizer == PolygonSymbolizer: 1280 fill = Fill(sym) 1281 fill.create_cssparameter('fill', '#AAAAAA') 1282 stroke = Stroke(sym) 1283 stroke.create_cssparameter('stroke', '#000000') 1284 stroke.create_cssparameter('stroke-width', '1') 1285 1286 return rule
1287
1288 1289 -class UserStyle(SLDNode):
1290 """ 1291 A UserStyle object. A UserStyle is a child of a L{StyledLayerDescriptor}. 1292 1293 @prop: Title 1294 1295 The title of the UserStyle. 1296 1297 I{Type}: string 1298 1299 @prop: Abstract 1300 1301 The abstract describing this UserStyle. 1302 1303 I{Type}: string 1304 1305 @prop: FeatureTypeStyle 1306 1307 The styling for the feature type. 1308 1309 I{Type}: L{FeatureTypeStyle} 1310 """
1311 - def __init__(self, parent, descendant=True):
1312 """ 1313 Create a new UserStyle node. 1314 1315 @type parent: L{NamedLayer} 1316 @param parent: The parent class object. 1317 @type descendant: boolean 1318 @param descendant: A flag indicating if this is a descendant node of the parent. 1319 """ 1320 super(UserStyle, self).__init__(parent, descendant=descendant) 1321 self._node = self._parent.xpath('sld:UserStyle', namespaces=SLDNode._nsmap)[0] 1322 1323 setattr(self.__class__, 'Title', SLDNode.makeproperty('sld', name='Title', 1324 docstring="The title of the UserStyle.")) 1325 setattr(self.__class__, 'Abstract', SLDNode.makeproperty('sld', name='Abstract', 1326 docstring="The abstract of the UserStyle.")) 1327 setattr(self.__class__, 'FeatureTypeStyle', SLDNode.makeproperty('sld', cls=FeatureTypeStyle, 1328 docstring="The feature type style of the UserStyle."))
1329
1330 - def normalize(self):
1331 """ 1332 Normalize this node and all child nodes prior to validation. The SLD 1333 is modified in place. 1334 """ 1335 if not self.FeatureTypeStyle is None: 1336 self.FeatureTypeStyle.normalize()
1337
1338 - def create_featuretypestyle(self):
1339 """ 1340 Create a L{FeatureTypeStyle} object, and attach it to this UserStyle. 1341 1342 @rtype: L{FeatureTypeStyle} 1343 @return: A newly created feature type style, attached to this node. 1344 """ 1345 return self.get_or_create_element('sld', 'FeatureTypeStyle')
1346
1347 1348 -class NamedLayer(SLDNode):
1349 """ 1350 A named layer contains a name and a user style. A NamedLayer is a child of 1351 a L{StyledLayerDescriptor}. 1352 1353 @prop: Name 1354 1355 The name of the UserStyle. 1356 1357 I{Type}: string 1358 1359 @prop: UserStyle 1360 1361 The custom styling for this named layer. 1362 1363 I{Type}: L{UserStyle} 1364 """
1365 - def __init__(self, parent, descendant=True):
1366 """ 1367 Create a new NamedLayer node. 1368 1369 @type parent: L{StyledLayerDescriptor} 1370 @param parent: The parent class object. 1371 @type descendant: boolean 1372 @param descendant: A flag indicating if this is a descendant node of the parent. 1373 """ 1374 super(NamedLayer, self).__init__(parent, descendant=descendant) 1375 self._node = self._parent.xpath('sld:NamedLayer', namespaces=SLDNode._nsmap)[0] 1376 1377 setattr(self.__class__, 'UserStyle', SLDNode.makeproperty('sld', cls=UserStyle, 1378 docstring="The UserStyle of the NamedLayer.")) 1379 setattr(self.__class__, 'Name', SLDNode.makeproperty('sld', name='Name', 1380 docstring="The name of the layer."))
1381
1382 - def normalize(self):
1383 """ 1384 Normalize this node and all child nodes prior to validation. The SLD 1385 is modified in place. 1386 """ 1387 if not self.UserStyle is None: 1388 self.UserStyle.normalize()
1389
1390 - def create_userstyle(self):
1391 """ 1392 Create a L{UserStyle} for this named layer. 1393 1394 @rtype: L{UserStyle} 1395 @return: A newly created user style, attached to this node. 1396 """ 1397 return self.get_or_create_element('sld', 'UserStyle')
1398
1399 1400 -class StyledLayerDescriptor(SLDNode):
1401 """ 1402 An object representation of an SLD document. 1403 1404 @prop: NamedLayer 1405 1406 The named layer that this styling applies to. 1407 1408 I{Type}: L{NamedLayer} 1409 """ 1410 1411 _cached_schema = None 1412 """A cached schema document, to prevent repeated web requests for the schema document.""" 1413
1414 - def __init__(self, sld_file=None):
1415 """ 1416 Create a new SLD document. If an sld file is provided, this constructor 1417 will fetch the SLD schema from the internet and validate the file 1418 against that schema. 1419 1420 @type sld_file: string 1421 @param sld_file: The name of a pre-existing SLD file. 1422 """ 1423 super(StyledLayerDescriptor, self).__init__(None) 1424 1425 if StyledLayerDescriptor._cached_schema is None: 1426 logging.debug('Storing new schema into cache.') 1427 1428 localschema = NamedTemporaryFile(delete=False) 1429 1430 localschema_backup_path = './StyledLayerDescriptor-backup.xsd' 1431 try: 1432 logging.debug('Cache hit for backup schema document.') 1433 localschema_backup = open(localschema_backup_path, 'rb') 1434 except IOError: 1435 logging.debug('Cache miss for backup schema document.') 1436 localschema_backup = open(localschema_backup_path, 'wb') 1437 1438 schema_url = 'http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd' 1439 resp = urlopen(schema_url) 1440 localschema_backup.write(resp.read()) 1441 resp.close() 1442 localschema_backup.close() 1443 localschema_backup = open(localschema_backup_path, 'rb') 1444 1445 localschema.write(localschema_backup.read()) 1446 localschema.close() 1447 localschema_backup.close() 1448 1449 localschema = open(localschema.name, 'rt') 1450 self._schemadoc = parse(localschema) 1451 localschema.close() 1452 1453 StyledLayerDescriptor._cached_schema = localschema.name 1454 else: 1455 logging.debug('Fetching schema from cache.') 1456 1457 localschema = open(StyledLayerDescriptor._cached_schema, 'rt') 1458 self._schemadoc = parse(localschema) 1459 localschema.close() 1460 1461 if not sld_file is None: 1462 self._node = parse(sld_file) 1463 self._schema = XMLSchema(self._schemadoc) 1464 if not self._schema.validate(self._node): 1465 logging.warn('SLD File "%s" does not validate against the SLD schema.', sld_file) 1466 else: 1467 self._node = Element("{%s}StyledLayerDescriptor" % SLDNode._nsmap['sld'], version="1.0.0", nsmap=SLDNode._nsmap) 1468 self._schema = None 1469 1470 setattr(self.__class__, 'NamedLayer', SLDNode.makeproperty('sld', cls=NamedLayer, 1471 docstring="The named layer of the SLD."))
1472
1473 - def __del__(self):
1474 """ 1475 Destroy the StyledLayerDescriptor object, and clear its cache. 1476 """ 1477 if not StyledLayerDescriptor._cached_schema is None: 1478 logging.debug('Clearing cached schema.') 1479 1480 os.remove(StyledLayerDescriptor._cached_schema) 1481 StyledLayerDescriptor._cached_schema = None
1482
1483 - def __deepcopy__(self, memo):
1484 """ 1485 Perform a deep copy. Instead of copying references to the schema 1486 object, create a new SLD, and deepcopy the SLD node. 1487 """ 1488 sld = StyledLayerDescriptor() 1489 sld._node = copy.deepcopy(self._node) 1490 return sld
1491
1492 - def normalize(self):
1493 """ 1494 Normalize this node and all child nodes prior to validation. The SLD 1495 is modified in place. 1496 """ 1497 if not self.NamedLayer is None: 1498 self.NamedLayer.normalize()
1499
1500 - def validate(self):
1501 """ 1502 Validate the current file against the SLD schema. This first normalizes 1503 the SLD document, then validates it. Any schema validation error messages 1504 are logged at the INFO level. 1505 1506 @rtype: boolean 1507 @return: A flag indicating if the SLD is valid. 1508 """ 1509 self.normalize() 1510 1511 if self._node is None: 1512 logging.debug('The node is empty, and cannot be validated.') 1513 return False 1514 1515 if self._schema is None: 1516 self._schema = XMLSchema(self._schemadoc) 1517 1518 is_valid = self._schema.validate(self._node) 1519 1520 for msg in self._schema.error_log: 1521 logging.info('Line:%d, Column:%d -- %s', msg.line, msg.column, msg.message) 1522 1523 return is_valid
1524 1525 @property
1526 - def version(self):
1527 """ 1528 Get the SLD version. 1529 """ 1530 return self._node.getroot().get('version')
1531 1532 @property
1533 - def xmlns(self):
1534 """ 1535 Get the XML Namespace. 1536 """ 1537 return self._node.getroot().nsmap[None]
1538
1539 - def create_namedlayer(self, name):
1540 """ 1541 Create a L{NamedLayer} in this SLD. 1542 1543 @type name: string 1544 @param name: The name of the layer. 1545 @rtype: L{NamedLayer} 1546 @return: The named layer, attached to this SLD. 1547 """ 1548 namedlayer = self.get_or_create_element('sld', 'NamedLayer') 1549 namedlayer.Name = name 1550 return namedlayer
1551
1552 - def as_sld(self, pretty_print=False):
1553 """ 1554 Serialize this SLD model into a string. 1555 1556 @rtype: string 1557 @returns: The content of the SLD. 1558 """ 1559 return tostring(self._node, pretty_print=pretty_print)
1560