001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/graphics/sld/SLDFactory.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2008 by: 006 EXSE, Department of Geography, University of Bonn 007 http://www.giub.uni-bonn.de/deegree/ 008 lat/lon GmbH 009 http://www.lat-lon.de 010 011 This library is free software; you can redistribute it and/or 012 modify it under the terms of the GNU Lesser General Public 013 License as published by the Free Software Foundation; either 014 version 2.1 of the License, or (at your option) any later version. 015 016 This library is distributed in the hope that it will be useful, 017 but WITHOUT ANY WARRANTY; without even the implied warranty of 018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 019 Lesser General Public License for more details. 020 021 You should have received a copy of the GNU Lesser General Public 022 License along with this library; if not, write to the Free Software 023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 024 025 Contact: 026 027 Andreas Poth 028 lat/lon GmbH 029 Aennchenstr. 19 030 53115 Bonn 031 Germany 032 E-Mail: poth@lat-lon.de 033 034 Prof. Dr. Klaus Greve 035 Department of Geography 036 University of Bonn 037 Meckenheimer Allee 166 038 53115 Bonn 039 Germany 040 E-Mail: greve@giub.uni-bonn.de 041 042 043 ---------------------------------------------------------------------------*/ 044 package org.deegree.graphics.sld; 045 046 import java.io.IOException; 047 import java.io.StringReader; 048 import java.net.MalformedURLException; 049 import java.net.URI; 050 import java.net.URL; 051 import java.util.ArrayList; 052 import java.util.HashMap; 053 import java.util.Iterator; 054 import java.util.LinkedList; 055 import java.util.List; 056 057 import org.deegree.datatypes.QualifiedName; 058 import org.deegree.framework.log.ILogger; 059 import org.deegree.framework.log.LoggerFactory; 060 import org.deegree.framework.xml.ElementList; 061 import org.deegree.framework.xml.NamespaceContext; 062 import org.deegree.framework.xml.XMLFragment; 063 import org.deegree.framework.xml.XMLParsingException; 064 import org.deegree.framework.xml.XMLTools; 065 import org.deegree.model.filterencoding.AbstractFilter; 066 import org.deegree.model.filterencoding.ComplexFilter; 067 import org.deegree.model.filterencoding.Expression; 068 import org.deegree.model.filterencoding.FalseFilter; 069 import org.deegree.model.filterencoding.Filter; 070 import org.deegree.model.filterencoding.FilterEvaluationException; 071 import org.deegree.model.filterencoding.LogicalOperation; 072 import org.deegree.model.filterencoding.Operation; 073 import org.deegree.model.filterencoding.OperationDefines; 074 import org.deegree.ogcbase.CommonNamespaces; 075 import org.deegree.ogcbase.OGCDocument; 076 import org.deegree.ogcbase.PropertyPath; 077 import org.w3c.dom.Element; 078 import org.w3c.dom.Node; 079 import org.w3c.dom.NodeList; 080 import org.w3c.dom.Text; 081 import org.xml.sax.SAXException; 082 083 /** 084 * Factory class for all mapped SLD-elements. 085 * <p> 086 * TODO: Default values for omitted elements (such as fill color) should better not be used in the 087 * construction of the corresponding objects (Fill), but marked as left out (to make it possible to 088 * differentiate between explicitly given values and default values). 089 * <p> 090 * 091 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> 092 * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider</a> 093 * @version $Revision: 12138 $ $Date: 2008-06-04 10:34:15 +0200 (Mi, 04 Jun 2008) $ 094 */ 095 public class SLDFactory { 096 097 private static final ILogger LOG = LoggerFactory.getLogger( SLDFactory.class ); 098 099 private static URI ogcNS = CommonNamespaces.OGCNS; 100 101 private static URI xlnNS = CommonNamespaces.XLNNS; 102 103 private static final String PSE = CommonNamespaces.SE_PREFIX + ":"; 104 105 private static NamespaceContext nsContext = CommonNamespaces.getNamespaceContext(); 106 107 private static XMLFragment sldDoc = null; 108 109 /** 110 * Creates a <tt>StyledLayerDescriptor</tt>-instance from the given XML-representation. 111 * <p> 112 * 113 * @param s 114 * contains the XML document 115 * @throws XMLParsingException 116 * if a syntactic or semantic error in the XML document is encountered 117 * @return the constructed <tt>StyledLayerDescriptor</tt>-instance 118 */ 119 public static synchronized StyledLayerDescriptor createSLD( String s ) 120 throws XMLParsingException { 121 StyledLayerDescriptor sld = null; 122 try { 123 sldDoc = new XMLFragment(); 124 sldDoc.load( new StringReader( s ), XMLFragment.DEFAULT_URL ); 125 sld = createSLD( sldDoc ); 126 } catch ( IOException e ) { 127 LOG.logDebug( e.getMessage(), e ); 128 throw new XMLParsingException( "IOException encountered while parsing SLD-Document" ); 129 } catch ( SAXException e ) { 130 LOG.logDebug( e.getMessage(), e ); 131 throw new XMLParsingException( "SAXException encountered while parsing SLD-Document" ); 132 } 133 134 return sld; 135 } 136 137 /** 138 * Creates a <tt>StyledLayerDescriptor</tt>-instance from a SLD document read from the passed 139 * URL 140 * 141 * @param url 142 * @return 143 * @throws XMLParsingException 144 */ 145 public static synchronized StyledLayerDescriptor createSLD( URL url ) 146 throws XMLParsingException { 147 StyledLayerDescriptor sld = null; 148 149 try { 150 sldDoc = new XMLFragment(); 151 sldDoc.load( url ); 152 sld = createSLD( sldDoc ); 153 } catch ( IOException e ) { 154 LOG.logError( e.getMessage(), e ); 155 throw new XMLParsingException( "IOException encountered while parsing SLD-Document" ); 156 } catch ( SAXException e ) { 157 LOG.logError( e.getMessage(), e ); 158 throw new XMLParsingException( "SAXException encountered while parsing SLD-Document" ); 159 } 160 161 return sld; 162 } 163 164 /** 165 * Creates a <tt>StyledLayerDescriptor</tt>-instance according to the contents of the 166 * DOM-subtree starting at the given 'StyledLayerDescriptor'-<tt>Element</tt>. 167 * <p> 168 * 169 * @param element 170 * the 'StyledLayerDescriptor'-<tt>Element</tt> 171 * @throws XMLParsingException 172 * if a syntactic or semantic error in the DOM-subtree is encountered 173 * @return the constructed <tt>StyledLayerDescriptor</tt>-instance 174 */ 175 public static StyledLayerDescriptor createSLD( XMLFragment sldDoc ) 176 throws XMLParsingException { 177 178 Element element = sldDoc.getRootElement(); 179 180 // optional: <Name> 181 String name = XMLTools.getStringValue( "Name", CommonNamespaces.SLDNS, element, null ); 182 183 // optional: <Title> 184 String title = XMLTools.getStringValue( "Title", CommonNamespaces.SLDNS, element, null ); 185 // optional: <Abstract> 186 String abstract_ = XMLTools.getStringValue( "Abstract", CommonNamespaces.SLDNS, element, null ); 187 // required: version-Attribute 188 String version = XMLTools.getRequiredAttrValue( "version", null, element ); 189 190 // optional: <NamedLayer>(s) / <UserLayer>(s) 191 NodeList nodelist = element.getChildNodes(); 192 ArrayList layerList = new ArrayList( 100 ); 193 194 for ( int i = 0; i < nodelist.getLength(); i++ ) { 195 if ( nodelist.item( i ) instanceof Element ) { 196 Element child = (Element) nodelist.item( i ); 197 String namespace = child.getNamespaceURI(); 198 if ( !CommonNamespaces.SLDNS.toASCIIString().equals( namespace ) ) { 199 continue; 200 } 201 202 String childName = child.getLocalName(); 203 if ( childName.equals( "NamedLayer" ) ) { 204 layerList.add( createNamedLayer( child ) ); 205 } else if ( childName.equals( "UserLayer" ) ) { 206 layerList.add( createUserLayer( child ) ); 207 } 208 } 209 } 210 211 AbstractLayer[] al = new AbstractLayer[layerList.size()]; 212 AbstractLayer[] layers = (AbstractLayer[]) layerList.toArray( al ); 213 214 return new StyledLayerDescriptor( name, title, version, abstract_, layers ); 215 } 216 217 private static Categorize createCategorize( Element root ) 218 throws XMLParsingException { 219 // ignore fallback value, we really implement it 220 // String fallbackValue = root.getAttribute( "fallbackValue" ); 221 222 Categorize categorize = new Categorize(); 223 224 // ignore lookup value element, should be set to "Rasterdata" 225 // Element lv = XMLTools.getElement( root, PSE + "LookupValue", nsContext ); 226 // ParameterValueType lookupValue = lv == null ? null : createParameterValueType( lv ); 227 // 228 // if ( lookupValue != null ) { 229 // categorize.setLookupValue( lookupValue ); 230 // } 231 232 List<Element> valueElements = XMLTools.getElements( root, PSE + "Value", nsContext ); 233 List<Element> thresholdElements = XMLTools.getElements( root, PSE + "Threshold", nsContext ); 234 235 LinkedList<ParameterValueType> values = new LinkedList<ParameterValueType>(); 236 LinkedList<ParameterValueType> thresholds = new LinkedList<ParameterValueType>(); 237 238 for ( Element e : valueElements ) { 239 values.add( createParameterValueType( e ) ); 240 } 241 242 for ( Element e : thresholdElements ) { 243 thresholds.add( createParameterValueType( e ) ); 244 } 245 246 categorize.setValues( values ); 247 categorize.setThresholds( thresholds ); 248 249 String tbt = root.getAttribute( "threshholdsBelongTo" ); 250 if ( tbt == null ) { 251 tbt = root.getAttribute( "thresholdsBelongTo" ); 252 } 253 254 ThresholdsBelongTo thresholdsBelongTo = null; 255 256 if ( tbt != null ) { 257 if ( tbt.equalsIgnoreCase( "succeeding" ) ) { 258 thresholdsBelongTo = ThresholdsBelongTo.SUCCEEDING; 259 } 260 if ( tbt.equalsIgnoreCase( "preceding" ) ) { 261 thresholdsBelongTo = ThresholdsBelongTo.PRECEDING; 262 } 263 } 264 265 if ( thresholdsBelongTo != null ) { 266 categorize.setThresholdsBelongTo( thresholdsBelongTo ); 267 } 268 269 return categorize; 270 } 271 272 /** 273 * 274 * @param root 275 * @param min 276 * @param max 277 * @return a raster symbolizer 278 * @throws XMLParsingException 279 */ 280 private static RasterSymbolizer createRasterSymbolizer( Element root, double min, double max ) 281 throws XMLParsingException { 282 RasterSymbolizer symbolizer = new RasterSymbolizer( min, max ); 283 284 Element opacity = XMLTools.getElement( root, PSE + "Opacity", nsContext ); 285 if ( opacity != null ) { 286 symbolizer.setOpacity( createParameterValueType( opacity ) ); 287 } 288 289 Element colorMap = XMLTools.getElement( root, PSE + "ColorMap", nsContext ); 290 if ( colorMap != null ) { 291 Element categorize = XMLTools.getElement( colorMap, PSE + "Categorize", nsContext ); 292 293 if ( categorize != null ) { 294 symbolizer.setCategorize( createCategorize( categorize ) ); 295 } 296 297 Element interpolate = XMLTools.getElement( colorMap, PSE + "Interpolate", nsContext ); 298 299 if ( interpolate != null ) { 300 symbolizer.setInterpolate( createInterpolate( interpolate ) ); 301 } 302 } 303 304 return symbolizer; 305 } 306 307 /** 308 * @param root 309 * @return an Interpolate object 310 * @throws XMLParsingException 311 */ 312 private static Interpolate createInterpolate( Element root ) 313 throws XMLParsingException { 314 String fallbackValue = root.getAttribute( "fallbackValue" ); 315 316 Interpolate interpolate = new Interpolate( fallbackValue ); 317 318 Element elem = XMLTools.getElement( root, PSE + "lookupValue", nsContext ); 319 if ( elem != null ) { 320 interpolate.setLookupValue( createParameterValueType( elem ) ); 321 } 322 323 String mode = root.getAttribute( "mode" ); 324 if ( mode != null ) { 325 if ( mode.equalsIgnoreCase( "linear" ) ) { 326 interpolate.setMode( Mode.LINEAR ); 327 } 328 if ( mode.equalsIgnoreCase( "cosine" ) ) { 329 LOG.logWarning( "Cosine interpolation is not supported." ); 330 interpolate.setMode( Mode.COSINE ); 331 } 332 if ( mode.equalsIgnoreCase( "cubic" ) ) { 333 LOG.logWarning( "Cubic interpolation is not supported." ); 334 interpolate.setMode( Mode.CUBIC ); 335 } 336 } 337 338 String method = root.getAttribute( "method" ); 339 if ( method != null ) { 340 if ( method.equalsIgnoreCase( "numeric" ) ) { 341 LOG.logWarning( "Numeric method is not supported, using color method anyway." ); 342 interpolate.setMethod( Method.NUMERIC ); 343 } 344 if ( method.equalsIgnoreCase( "color" ) ) { 345 interpolate.setMethod( Method.COLOR ); 346 } 347 } 348 349 List<Element> ips = XMLTools.getElements( root, PSE + "InterpolationPoint", nsContext ); 350 351 interpolate.setInterpolationPoints( createInterpolationPoints( ips ) ); 352 353 return interpolate; 354 } 355 356 private static List<InterpolationPoint> createInterpolationPoints( List<Element> ips ) 357 throws XMLParsingException { 358 List<InterpolationPoint> ps = new ArrayList<InterpolationPoint>( ips.size() ); 359 360 for ( Element elem : ips ) { 361 double data = XMLTools.getRequiredNodeAsDouble( elem, PSE + "Data", nsContext ); 362 Element e = XMLTools.getRequiredElement( elem, PSE + "Value", nsContext ); 363 try { 364 String val = createParameterValueType( e ).evaluate( null ).substring( 1 ); 365 ps.add( new InterpolationPoint( data, val ) ); 366 } catch ( NumberFormatException e1 ) { 367 LOG.logError( "A 'Value' in an 'InterpolationPoint' could not be parsed.", e1 ); 368 } catch ( FilterEvaluationException e1 ) { 369 LOG.logError( "A 'Value' in an 'InterpolationPoint' could not be parsed.", e1 ); 370 } 371 } 372 373 return ps; 374 } 375 376 /** 377 * Creates a <tt>TextSymbolizer</tt>-instance according to the contents of the DOM-subtree 378 * starting at the given 'TextSymbolizer'-<tt>Element</tt>. 379 * <p> 380 * 381 * @param element 382 * the 'TextSymbolizer'-<tt>Element</tt> 383 * @param min 384 * scale-constraint to be used 385 * @param max 386 * scale-constraint to be used 387 * @throws XMLParsingException 388 * if a syntactic or semantic error in the DOM-subtree is encountered 389 * @return the constructed <tt>TextSymbolizer</tt>-instance 390 */ 391 private static TextSymbolizer createTextSymbolizer( Element element, double min, double max ) 392 throws XMLParsingException { 393 394 // optional: <Geometry> 395 Geometry geometry = null; 396 Element geometryElement = XMLTools.getChildElement( "Geometry", CommonNamespaces.SLDNS, element ); 397 398 if ( geometryElement != null ) { 399 geometry = createGeometry( geometryElement ); 400 } 401 402 // optional: <Label> 403 ParameterValueType label = null; 404 Element labelElement = XMLTools.getChildElement( "Label", CommonNamespaces.SLDNS, element ); 405 406 if ( labelElement != null ) { 407 label = createParameterValueType( labelElement ); 408 } 409 410 // optional: <Font> 411 Font font = null; 412 Element fontElement = XMLTools.getChildElement( "Font", CommonNamespaces.SLDNS, element ); 413 414 if ( fontElement != null ) { 415 font = createFont( fontElement ); 416 } 417 418 // optional: <LabelPlacement> 419 LabelPlacement labelPlacement = null; 420 Element lpElement = XMLTools.getChildElement( "LabelPlacement", CommonNamespaces.SLDNS, element ); 421 422 if ( lpElement != null ) { 423 labelPlacement = createLabelPlacement( lpElement ); 424 } else { 425 PointPlacement pp = StyleFactory.createPointPlacement(); 426 labelPlacement = StyleFactory.createLabelPlacement( pp ); 427 } 428 429 // optional: <Halo> 430 Halo halo = null; 431 Element haloElement = XMLTools.getChildElement( "Halo", CommonNamespaces.SLDNS, element ); 432 433 if ( haloElement != null ) { 434 halo = createHalo( haloElement ); 435 } 436 437 // optional: <Fill> 438 Fill fill = null; 439 440 TextSymbolizer ps = null; 441 String respClass = XMLTools.getAttrValue( element, null, "responsibleClass", null ); 442 if ( respClass == null ) { 443 ps = new TextSymbolizer( geometry, label, font, labelPlacement, halo, fill, min, max ); 444 } else { 445 ps = new TextSymbolizer( geometry, respClass, label, font, labelPlacement, halo, fill, min, max ); 446 } 447 448 return ps; 449 } 450 451 /** 452 * Creates a <tt>Halo</tt>-instance according to the contents of the DOM-subtree starting at 453 * the given 'Halo'-<tt>Element</tt>. 454 * <p> 455 * 456 * @param element 457 * the 'Halo'-<tt>Element</tt> 458 * @throws XMLParsingException 459 * if a syntactic or semantic error in the DOM-subtree is encountered 460 * @return the constructed <tt>Halo</tt>-instance 461 */ 462 private static Halo createHalo( Element element ) 463 throws XMLParsingException { 464 // optional: <Radius> 465 ParameterValueType radius = null; 466 Element radiusElement = XMLTools.getChildElement( "Radius", CommonNamespaces.SLDNS, element ); 467 468 if ( radiusElement != null ) { 469 radius = createParameterValueType( radiusElement ); 470 } 471 472 // optional: <Fill> 473 Fill fill = null; 474 Element fillElement = XMLTools.getChildElement( "Fill", CommonNamespaces.SLDNS, element ); 475 476 if ( fillElement != null ) { 477 fill = createFill( fillElement ); 478 } 479 480 // optional: <Stroke> 481 Stroke stroke = null; 482 Element strokeElement = XMLTools.getChildElement( "Stroke", CommonNamespaces.SLDNS, element ); 483 484 if ( strokeElement != null ) { 485 stroke = createStroke( strokeElement ); 486 } 487 488 return new Halo( radius, fill, stroke ); 489 } 490 491 /** 492 * Creates a <tt>LabelPlacement</tt>-instance according to the contents of the DOM-subtree 493 * starting at the given 'LabelPlacement'-<tt>Element</tt>. 494 * <p> 495 * 496 * @param element 497 * the 'LabelPlacement'-<tt>Element</tt> 498 * @throws XMLParsingException 499 * if a syntactic or semantic error in the DOM-subtree is encountered 500 * @return the constructed <tt>LabelPlacement</tt>-instance 501 */ 502 private static LabelPlacement createLabelPlacement( Element element ) 503 throws XMLParsingException { 504 LabelPlacement labelPlacement = null; 505 506 // required: <PointPlacement> / <LinePlacement> 507 NodeList nodelist = element.getChildNodes(); 508 PointPlacement pPlacement = null; 509 LinePlacement lPlacement = null; 510 511 for ( int i = 0; i < nodelist.getLength(); i++ ) { 512 if ( nodelist.item( i ) instanceof Element ) { 513 Element child = (Element) nodelist.item( i ); 514 String namespace = child.getNamespaceURI(); 515 516 if ( !CommonNamespaces.SLDNS.toASCIIString().equals( namespace ) ) { 517 continue; 518 } 519 520 String childName = child.getLocalName(); 521 522 if ( childName.equals( "PointPlacement" ) ) { 523 pPlacement = createPointPlacement( child ); 524 } else if ( childName.equals( "LinePlacement" ) ) { 525 lPlacement = createLinePlacement( child ); 526 } 527 } 528 } 529 530 if ( ( pPlacement != null ) && ( lPlacement == null ) ) { 531 labelPlacement = new LabelPlacement( pPlacement ); 532 } else if ( ( pPlacement == null ) && ( lPlacement != null ) ) { 533 labelPlacement = new LabelPlacement( lPlacement ); 534 } else { 535 throw new XMLParsingException( "Element 'LabelPlacement' must contain exactly one " 536 + "'PointPlacement'- or one 'LinePlacement'-element!" ); 537 } 538 539 return labelPlacement; 540 } 541 542 /** 543 * Creates a <tt>PointPlacement</tt>-instance according to the contents of the DOM-subtree 544 * starting at the given 'PointPlacement'-<tt>Element</tt>. 545 * <p> 546 * 547 * @param element 548 * the 'PointPlacement'-<tt>Element</tt> 549 * @throws XMLParsingException 550 * if a syntactic or semantic error in the DOM-subtree is encountered 551 * @return the constructed <tt>PointPlacement</tt>-instance 552 */ 553 private static PointPlacement createPointPlacement( Element element ) 554 throws XMLParsingException { 555 556 // optional: auto-Attribute (this is deegree-specific) 557 boolean auto = false; 558 String autoStr = XMLTools.getAttrValue( element, null, "auto", null ); 559 560 if ( autoStr != null && autoStr.equals( "true" ) ) { 561 auto = true; 562 } 563 564 // optional: <AnchorPoint> 565 ParameterValueType[] anchorPoint = null; 566 Element apElement = XMLTools.getChildElement( "AnchorPoint", CommonNamespaces.SLDNS, element ); 567 568 if ( apElement != null ) { 569 anchorPoint = new ParameterValueType[2]; 570 571 Element apXElement = XMLTools.getChildElement( "AnchorPointX", CommonNamespaces.SLDNS, apElement ); 572 Element apYElement = XMLTools.getChildElement( "AnchorPointY", CommonNamespaces.SLDNS, apElement ); 573 574 if ( ( apXElement == null ) || ( apYElement == null ) ) { 575 throw new XMLParsingException( "Element 'AnchorPoint' must contain exactly one " 576 + "'AnchorPointX'- and one 'AnchorPointY'-element!" ); 577 } 578 579 anchorPoint[0] = createParameterValueType( apXElement ); 580 anchorPoint[1] = createParameterValueType( apYElement ); 581 } 582 583 // optional: <Displacement> 584 ParameterValueType[] displacement = null; 585 Element dElement = XMLTools.getChildElement( "Displacement", CommonNamespaces.SLDNS, element ); 586 587 if ( dElement != null ) { 588 displacement = new ParameterValueType[2]; 589 590 Element dXElement = XMLTools.getChildElement( "DisplacementX", CommonNamespaces.SLDNS, dElement ); 591 Element dYElement = XMLTools.getChildElement( "DisplacementY", CommonNamespaces.SLDNS, dElement ); 592 593 if ( ( dXElement == null ) || ( dYElement == null ) ) { 594 throw new XMLParsingException( "Element 'Displacement' must contain exactly one " 595 + "'DisplacementX'- and one 'DisplacementY'-element!" ); 596 } 597 598 displacement[0] = createParameterValueType( dXElement ); 599 displacement[1] = createParameterValueType( dYElement ); 600 } 601 602 // optional: <Rotation> 603 ParameterValueType rotation = null; 604 Element rElement = XMLTools.getChildElement( "Rotation", CommonNamespaces.SLDNS, element ); 605 606 if ( rElement != null ) { 607 rotation = createParameterValueType( rElement ); 608 } 609 610 return new PointPlacement( anchorPoint, displacement, rotation, auto ); 611 } 612 613 /** 614 * Creates a <tt>LinePlacement</tt>-instance according to the contents of the DOM-subtree 615 * starting at the given 'LinePlacement'-<tt>Element</tt>. 616 * <p> 617 * 618 * @param element 619 * the 'LinePlacement'-<tt>Element</tt> 620 * @throws XMLParsingException 621 * if a syntactic or semantic error in the DOM-subtree is encountered 622 * @return the constructed <tt>LinePlacement</tt>-instance 623 */ 624 private static LinePlacement createLinePlacement( Element element ) 625 throws XMLParsingException { 626 627 // optional: <PerpendicularOffset> 628 ParameterValueType pOffset = null; 629 Element pOffsetElement = XMLTools.getChildElement( "PerpendicularOffset", CommonNamespaces.SLDNS, element ); 630 631 if ( pOffsetElement != null ) { 632 pOffset = createParameterValueType( pOffsetElement ); 633 } 634 635 // optional: <Gap> (this is deegree-specific) 636 ParameterValueType gap = null; 637 Element gapElement = XMLTools.getChildElement( "Gap", CommonNamespaces.SLDNS, element ); 638 639 if ( gapElement != null ) { 640 gap = createParameterValueType( gapElement ); 641 } 642 643 // optional: <LineWidth> (this is deegree-specific) 644 ParameterValueType lineWidth = null; 645 Element lineWidthElement = XMLTools.getChildElement( "LineWidth", CommonNamespaces.SLDNS, element ); 646 647 if ( lineWidthElement != null ) { 648 lineWidth = createParameterValueType( lineWidthElement ); 649 } 650 651 return new LinePlacement( pOffset, lineWidth, gap ); 652 } 653 654 /** 655 * Creates a <tt>Font</tt>-instance according to the contents of the DOM-subtree starting at 656 * the given 'Font'-<tt>Element</tt>. 657 * <p> 658 * 659 * @param element 660 * the 'Font'-<tt>Element</tt> 661 * @throws XMLParsingException 662 * if a syntactic or semantic error in the DOM-subtree is encountered 663 * @return the constructed <tt>Font</tt>-instance 664 */ 665 private static Font createFont( Element element ) 666 throws XMLParsingException { 667 668 // optional: <CssParameter>s 669 ElementList nl = XMLTools.getChildElements( "CssParameter", CommonNamespaces.SLDNS, element ); 670 HashMap cssParams = new HashMap( nl.getLength() ); 671 672 for ( int i = 0; i < nl.getLength(); i++ ) { 673 CssParameter cssParam = createCssParameter( nl.item( i ) ); 674 cssParams.put( cssParam.getName(), cssParam ); 675 } 676 677 return new Font( cssParams ); 678 } 679 680 /** 681 * Creates a <tt>ParameterValueType</tt>-instance according to the contents of the 682 * DOM-subtree starting at the given <tt>Element</tt>. 683 * <p> 684 * 685 * @param element 686 * the <tt>Element</tt> (must be of the type sld:ParameterValueType) 687 * @throws XMLParsingException 688 * if a syntactic or semantic error in the DOM-subtree is encountered 689 * @return the constructed <tt>ParameterValueType</tt>-instance 690 */ 691 private static ParameterValueType createParameterValueType( Element element ) 692 throws XMLParsingException { 693 // mix of text nodes and <wfs:Expression>-elements 694 ArrayList componentList = new ArrayList(); 695 NodeList nl = element.getChildNodes(); 696 697 for ( int i = 0; i < nl.getLength(); i++ ) { 698 Node node = nl.item( i ); 699 700 switch ( node.getNodeType() ) { 701 case Node.TEXT_NODE: { 702 componentList.add( node.getNodeValue() ); 703 break; 704 } 705 case Node.ELEMENT_NODE: { 706 Expression expression = Expression.buildFromDOM( (Element) node ); 707 componentList.add( expression ); 708 break; 709 } 710 default: 711 throw new XMLParsingException( "Elements of type 'ParameterValueType' may only " 712 + "consist of CDATA and 'ogc:Expression'-elements!" ); 713 } 714 } 715 716 Object[] components = componentList.toArray( new Object[componentList.size()] ); 717 return new ParameterValueType( components ); 718 } 719 720 /** 721 * Creates a <tt>NamedStyle</tt>-instance according to the contents of the DOM-subtree 722 * starting at the given 'NamedStyle'-<tt>Element</tt>. 723 * <p> 724 * 725 * @param element 726 * the 'NamedStyle'-<tt>Element</tt> 727 * @throws XMLParsingException 728 * if a syntactic or semantic error in the DOM-subtree is encountered 729 * @return the constructed <tt>NamedStyle</tt>-instance 730 */ 731 private static NamedStyle createNamedStyle( Element element ) 732 throws XMLParsingException { 733 // required: <Name> 734 String name = XMLTools.getRequiredStringValue( "Name", CommonNamespaces.SLDNS, element ); 735 736 return new NamedStyle( name ); 737 } 738 739 /** 740 * 741 */ 742 public static NamedStyle createNamedStyle( String name ) { 743 return new NamedStyle( name ); 744 } 745 746 /** 747 * Creates a <tt>RemoteOWS</tt>-instance according to the contents of the DOM-subtree 748 * starting at the given 'RemoteOWS'-<tt>Element</tt>. 749 * <p> 750 * 751 * @param element 752 * the 'RemoteOWS'-<tt>Element</tt> 753 * @throws XMLParsingException 754 * if a syntactic or semantic error in the DOM-subtree is encountered 755 * @return the constructed <tt>RemoteOWS</tt>-instance 756 */ 757 private static RemoteOWS createRemoteOWS( Element element ) 758 throws XMLParsingException { 759 // required: <Service> 760 String service = XMLTools.getRequiredStringValue( "Service", CommonNamespaces.SLDNS, element ); 761 762 if ( !( service.equals( "WFS" ) || service.equals( "WCS" ) ) ) { 763 throw new XMLParsingException( "Value ('" + service + "') of element 'service' is invalid. " 764 + "Allowed values are: 'WFS' and 'WCS'." ); 765 } 766 767 // required: <OnlineResource> 768 Element onlineResourceElement = XMLTools.getRequiredChildElement( "OnlineResource", CommonNamespaces.SLDNS, 769 element ); 770 String href = XMLTools.getRequiredAttrValue( "xlink:href", null, onlineResourceElement ); 771 URL url = null; 772 773 try { 774 url = new URL( href ); 775 } catch ( MalformedURLException e ) { 776 LOG.logDebug( e.getMessage(), e ); 777 throw new XMLParsingException( "Value ('" + href + "') of attribute 'href' of " 778 + "element 'OnlineResoure' does not denote a valid URL" ); 779 } 780 781 return new RemoteOWS( service, url ); 782 } 783 784 /** 785 * Creates a <tt>NamedLayer</tt>-instance according to the contents of the DOM-subtree 786 * starting at the given 'UserLayer'-<tt>Element</tt>. 787 * <p> 788 * 789 * @param element 790 * the 'NamedLayer'-<tt>Element</tt> 791 * @throws XMLParsingException 792 * if a syntactic or semantic error in the DOM-subtree is encountered 793 * @return the constructed <tt>NamedLayer</tt>-instance 794 */ 795 private static NamedLayer createNamedLayer( Element element ) 796 throws XMLParsingException { 797 // required: <Name> 798 String name = XMLTools.getRequiredStringValue( "Name", CommonNamespaces.SLDNS, element ); 799 800 // optional: <LayerFeatureConstraints> 801 LayerFeatureConstraints lfc = null; 802 Element lfcElement = XMLTools.getChildElement( "LayerFeatureConstraints", CommonNamespaces.SLDNS, element ); 803 804 if ( lfcElement != null ) { 805 lfc = createLayerFeatureConstraints( lfcElement ); 806 } 807 808 // optional: <NamedStyle>(s) / <UserStyle>(s) 809 NodeList nodelist = element.getChildNodes(); 810 ArrayList styleList = new ArrayList(); 811 812 for ( int i = 0; i < nodelist.getLength(); i++ ) { 813 if ( nodelist.item( i ) instanceof Element ) { 814 Element child = (Element) nodelist.item( i ); 815 String namespace = child.getNamespaceURI(); 816 817 if ( !CommonNamespaces.SLDNS.toASCIIString().equals( namespace ) ) { 818 continue; 819 } 820 821 String childName = child.getLocalName(); 822 823 if ( childName.equals( "NamedStyle" ) ) { 824 styleList.add( createNamedStyle( child ) ); 825 } else if ( childName.equals( "UserStyle" ) ) { 826 styleList.add( createUserStyle( child ) ); 827 } 828 } 829 } 830 831 AbstractStyle[] styles = (AbstractStyle[]) styleList.toArray( new AbstractStyle[styleList.size()] ); 832 833 return new NamedLayer( name, lfc, styles ); 834 } 835 836 /** 837 * 838 */ 839 public static NamedLayer createNamedLayer( String name, LayerFeatureConstraints layerFeatureConstraints, 840 AbstractStyle[] styles ) { 841 return new NamedLayer( name, layerFeatureConstraints, styles ); 842 } 843 844 /** 845 * Creates a <tt>UserLayer</tt>-instance according to the contents of the DOM-subtree 846 * starting at the given 'UserLayer'-<tt>Element</tt>. 847 * <p> 848 * 849 * @param element 850 * the 'UserLayer'-<tt>Element</tt> 851 * @throws XMLParsingException 852 * if a syntactic or semantic error in the DOM-subtree is encountered 853 * @return the constructed <tt>UserLayer</tt>-instance 854 */ 855 private static UserLayer createUserLayer( Element element ) 856 throws XMLParsingException { 857 // optional: <Name> 858 String name = XMLTools.getStringValue( "Name", CommonNamespaces.SLDNS, element, null ); 859 860 // optional: <RemoteOWS> 861 RemoteOWS remoteOWS = null; 862 Element remoteOWSElement = XMLTools.getChildElement( "RemoteOWS", CommonNamespaces.SLDNS, element ); 863 864 if ( remoteOWSElement != null ) { 865 remoteOWS = createRemoteOWS( remoteOWSElement ); 866 } 867 868 // required: <LayerFeatureConstraints> 869 LayerFeatureConstraints lfc = null; 870 Element lfcElement = XMLTools.getRequiredChildElement( "LayerFeatureConstraints", CommonNamespaces.SLDNS, 871 element ); 872 lfc = createLayerFeatureConstraints( lfcElement ); 873 874 // optional: <UserStyle>(s) 875 ElementList nodelist = XMLTools.getChildElements( "UserStyle", CommonNamespaces.SLDNS, element ); 876 UserStyle[] styles = new UserStyle[nodelist.getLength()]; 877 for ( int i = 0; i < nodelist.getLength(); i++ ) { 878 styles[i] = createUserStyle( nodelist.item( i ) ); 879 } 880 881 return new UserLayer( name, lfc, styles, remoteOWS ); 882 } 883 884 /** 885 * Creates a <tt>FeatureTypeConstraint</tt>-instance according to the contents of the 886 * DOM-subtree starting at the given 'FeatureTypeConstraint'-<tt>Element</tt>. 887 * <p> 888 * 889 * @param element 890 * the 'FeatureTypeConstraint'-<tt>Element</tt> 891 * @throws XMLParsingException 892 * if a syntactic or semantic error in the DOM-subtree is encountered 893 * @return the constructed <tt>FeatureTypeConstraint</tt>-instance 894 */ 895 private static FeatureTypeConstraint createFeatureTypeConstraint( Element element ) 896 throws XMLParsingException { 897 // optional: <Name> 898 Node node = XMLTools.getNode( element, "sld:FeatureTypeName/text()", CommonNamespaces.getNamespaceContext() ); 899 900 QualifiedName name; 901 if ( node == null ) { 902 name = null; 903 } else { 904 name = XMLTools.getQualifiedNameValue( node ); 905 } 906 907 // optional: <Filter> 908 Filter filter = null; 909 Element filterElement = XMLTools.getChildElement( "Filter", ogcNS, element ); 910 911 if ( filterElement != null ) { 912 filter = AbstractFilter.buildFromDOM( filterElement ); 913 } 914 915 // optional: <Extent>(s) 916 ElementList nodelist = XMLTools.getChildElements( "Extent", CommonNamespaces.SLDNS, element ); 917 Extent[] extents = new Extent[nodelist.getLength()]; 918 919 for ( int i = 0; i < nodelist.getLength(); i++ ) { 920 extents[i] = createExtent( nodelist.item( i ) ); 921 } 922 923 return new FeatureTypeConstraint( name, filter, extents ); 924 } 925 926 /** 927 * Creates an <tt>Extent</tt>-instance according to the contents of the DOM-subtree starting 928 * at the given 'Extent'-<tt>Element</tt>. 929 * <p> 930 * 931 * @param element 932 * the 'Extent'-<tt>Element</tt> 933 * @throws XMLParsingException 934 * if a syntactic or semantic error in the DOM-subtree is encountered 935 * @return the constructed <tt>Extent</tt>-instance 936 */ 937 private static Extent createExtent( Element element ) 938 throws XMLParsingException { 939 // required: <Name> 940 String name = XMLTools.getRequiredStringValue( "Name", CommonNamespaces.SLDNS, element ); 941 // required: <Value> 942 String value = XMLTools.getRequiredStringValue( "Value", CommonNamespaces.SLDNS, element ); 943 944 return new Extent( name, value ); 945 } 946 947 /** 948 * Creates a <tt>LayerFeatureConstraints</tt>-instance according to the contents of the 949 * DOM-subtree starting at the given 'LayerFeatureConstraints'-<tt>Element</tt>. 950 * <p> 951 * 952 * @param element 953 * the 'LayerFeatureConstraints'-<tt>Element</tt> 954 * @throws XMLParsingException 955 * if a syntactic or semantic error in the DOM-subtree is encountered 956 * @return the constructed <tt>LayerFeatureConstraints</tt>-instance 957 */ 958 public static LayerFeatureConstraints createLayerFeatureConstraints( Element element ) 959 throws XMLParsingException { 960 // required: <FeatureTypeConstraint>(s) 961 ElementList nodelist = XMLTools.getChildElements( "FeatureTypeConstraint", CommonNamespaces.SLDNS, element ); 962 FeatureTypeConstraint[] ftcs = new FeatureTypeConstraint[nodelist.getLength()]; 963 964 for ( int i = 0; i < nodelist.getLength(); i++ ) { 965 ftcs[i] = createFeatureTypeConstraint( nodelist.item( i ) ); 966 } 967 968 return new LayerFeatureConstraints( ftcs ); 969 } 970 971 /** 972 * Creates a <tt>UserStyle</tt>-instance according to the contents of the DOM-subtree 973 * starting at the given 'UserStyle'-<tt>Element</tt>. 974 * <p> 975 * 976 * @param element 977 * the 'UserStyle'-<tt>Element</tt> 978 * @throws XMLParsingException 979 * if a syntactic or semantic error in the DOM-subtree is encountered 980 * @return the constructed <tt>UserStyle</tt>-instance 981 */ 982 private static UserStyle createUserStyle( Element element ) 983 throws XMLParsingException { 984 // optional: <Name> 985 String name = XMLTools.getStringValue( "Name", CommonNamespaces.SLDNS, element, null ); 986 // optional: <Title> 987 String title = XMLTools.getStringValue( "Title", CommonNamespaces.SLDNS, element, null ); 988 // optional: <Abstract> 989 String abstract_ = XMLTools.getStringValue( "Abstract", CommonNamespaces.SLDNS, element, null ); 990 991 // optional: <IsDefault> 992 String defaultString = XMLTools.getStringValue( "IsDefault", CommonNamespaces.SLDNS, element, null ); 993 boolean isDefault = false; 994 995 if ( defaultString != null ) { 996 if ( defaultString.equals( "1" ) ) { 997 isDefault = true; 998 } 999 } 1000 1001 // required: <FeatureTypeStyle> (s) 1002 ElementList nl = XMLTools.getChildElements( "FeatureTypeStyle", CommonNamespaces.SLDNS, element ); 1003 FeatureTypeStyle[] styles = new FeatureTypeStyle[nl.getLength()]; 1004 1005 if ( styles.length == 0 ) { 1006 throw new XMLParsingException( "Required child-element 'FeatureTypeStyle' of element " 1007 + "'UserStyle' is missing!" ); 1008 } 1009 1010 for ( int i = 0; i < nl.getLength(); i++ ) { 1011 styles[i] = createFeatureTypeStyle( nl.item( i ) ); 1012 } 1013 1014 return new UserStyle( name, title, abstract_, isDefault, styles ); 1015 } 1016 1017 /** 1018 * Creates a <tt>FeatureTypeStyle</tt>-instance according to the contents of the DOM-subtree 1019 * starting at the given 'FeatureTypeStyle'-<tt>Element</tt>. 1020 * <p> 1021 * TODO: The ElseFilter currently does not work correctly with FeatureFilters. 1022 * <p> 1023 * 1024 * @param element 1025 * the 'FeatureTypeStyle'-<tt>Element</tt> 1026 * @throws XMLParsingException 1027 * if a syntactic or semantic error in the DOM-subtree is encountered 1028 * @return the constructed <tt>FeatureTypeStyle</tt>-instance 1029 */ 1030 public static FeatureTypeStyle createFeatureTypeStyle( Element element ) 1031 throws XMLParsingException { 1032 // optional: <Name> 1033 String name = XMLTools.getStringValue( "Name", CommonNamespaces.SLDNS, element, null ); 1034 // optional: <Title> 1035 String title = XMLTools.getStringValue( "Title", CommonNamespaces.SLDNS, element, null ); 1036 // optional: <Abstract> 1037 String abstract_ = XMLTools.getStringValue( "Abstract", CommonNamespaces.SLDNS, element, null ); 1038 // optional: <FeatureTypeName> 1039 String featureTypeName = XMLTools.getStringValue( "FeatureTypeName", CommonNamespaces.SLDNS, element, null ); 1040 1041 // optional: several <Rule> / <SemanticTypeIdentifier> 1042 NodeList nodelist = element.getChildNodes(); 1043 ArrayList<Rule> ruleList = new ArrayList<Rule>(); 1044 ArrayList<String> typeIdentifierList = new ArrayList<String>(); 1045 1046 // collect Filters of all Rules 1047 ArrayList<Filter> filters = new ArrayList<Filter>(); 1048 // collect all Rules that have an ElseFilter 1049 ArrayList<Rule> elseRules = new ArrayList<Rule>(); 1050 1051 for ( int i = 0; i < nodelist.getLength(); i++ ) { 1052 if ( nodelist.item( i ) instanceof Element ) { 1053 Element child = (Element) nodelist.item( i ); 1054 String namespace = child.getNamespaceURI(); 1055 if ( !CommonNamespaces.SLDNS.toString().equals( namespace ) ) { 1056 continue; 1057 } 1058 1059 String childName = child.getLocalName(); 1060 1061 if ( childName.equals( "Rule" ) ) { 1062 Rule rule = createRule( child ); 1063 if ( rule.hasElseFilter() ) { 1064 elseRules.add( rule ); 1065 } else if ( rule.getFilter() == null || rule.getFilter() instanceof ComplexFilter ) { 1066 filters.add( rule.getFilter() ); 1067 } 1068 ruleList.add( rule ); 1069 } else if ( childName.equals( "SemanticTypeIdentifier" ) ) { 1070 typeIdentifierList.add( XMLTools.getStringValue( child ) ); 1071 } 1072 } 1073 } 1074 1075 // compute and set the ElseFilter for all ElseFilter-Rules 1076 Filter elseFilter = null; 1077 // a Rule exists with no Filter at all -> elseFilter = false 1078 if ( filters.contains( null ) ) { 1079 elseFilter = new FalseFilter(); 1080 // one Rule with a Filter exists -> elseFilter = NOT Filter 1081 } else if ( filters.size() == 1 ) { 1082 elseFilter = new ComplexFilter( OperationDefines.NOT ); 1083 List<Operation> arguments = ( (LogicalOperation) ( (ComplexFilter) elseFilter ).getOperation() ).getArguments(); 1084 ComplexFilter complexFilter = (ComplexFilter) filters.get( 0 ); 1085 arguments.add( complexFilter.getOperation() ); 1086 // several Rules with Filters exist -> elseFilter = NOT (Filter1 OR Filter2 OR...) 1087 } else if ( filters.size() > 1 ) { 1088 ComplexFilter innerFilter = new ComplexFilter( OperationDefines.OR ); 1089 elseFilter = new ComplexFilter( innerFilter, null, OperationDefines.NOT ); 1090 List<Operation> arguments = ( (LogicalOperation) innerFilter.getOperation() ).getArguments(); 1091 Iterator it = filters.iterator(); 1092 while ( it.hasNext() ) { 1093 ComplexFilter complexFilter = (ComplexFilter) it.next(); 1094 arguments.add( complexFilter.getOperation() ); 1095 } 1096 } 1097 Iterator it = elseRules.iterator(); 1098 while ( it.hasNext() ) { 1099 ( (Rule) it.next() ).setFilter( elseFilter ); 1100 } 1101 1102 Rule[] rules = ruleList.toArray( new Rule[ruleList.size()] ); 1103 String[] typeIdentifiers = typeIdentifierList.toArray( new String[typeIdentifierList.size()] ); 1104 1105 return new FeatureTypeStyle( name, title, abstract_, featureTypeName, typeIdentifiers, rules ); 1106 } 1107 1108 /** 1109 * Creates a <tt>Rule</tt>-instance according to the contents of the DOM-subtree starting at 1110 * the given 'Rule'-<tt>Element</tt>. 1111 * <p> 1112 * 1113 * @param element 1114 * the 'Rule'-<tt>Element</tt> 1115 * @throws XMLParsingException 1116 * if a syntactic or semantic error in the DOM-subtree is encountered 1117 * @return the constructed <tt>Rule</tt>-instance 1118 */ 1119 private static Rule createRule( Element element ) 1120 throws XMLParsingException { 1121 // optional: <Name> 1122 String name = XMLTools.getStringValue( "Name", CommonNamespaces.SLDNS, element, null ); 1123 // optional: <Title> 1124 String title = XMLTools.getStringValue( "Title", CommonNamespaces.SLDNS, element, null ); 1125 // optional: <Abstract> 1126 String abstract_ = XMLTools.getStringValue( "Abstract", CommonNamespaces.SLDNS, element, null ); 1127 1128 // optional: <LegendGraphic> 1129 LegendGraphic legendGraphic = null; 1130 Element legendGraphicElement = XMLTools.getChildElement( "LegendGraphic", CommonNamespaces.SLDNS, element ); 1131 1132 if ( legendGraphicElement != null ) { 1133 legendGraphic = createLegendGraphic( legendGraphicElement ); 1134 } 1135 1136 // optional: <Filter> 1137 boolean isAnElseFilter = false; 1138 Filter filter = null; 1139 Element filterElement = XMLTools.getChildElement( "Filter", ogcNS, element ); 1140 if ( filterElement != null ) { 1141 filter = AbstractFilter.buildFromDOM( filterElement ); 1142 } 1143 1144 // optional: <ElseFilter> 1145 Element elseFilterElement = XMLTools.getChildElement( "ElseFilter", CommonNamespaces.SLDNS, element ); 1146 if ( elseFilterElement != null ) { 1147 isAnElseFilter = true; 1148 } 1149 1150 if ( ( filterElement != null ) && ( elseFilterElement != null ) ) { 1151 throw new XMLParsingException( "Element 'Rule' may contain a 'Filter'- or " 1152 + "an 'ElseFilter'-element, but not both!" ); 1153 } 1154 1155 // optional: <MinScaleDenominator> 1156 double min = XMLTools.getNodeAsDouble( element, "sld:MinScaleDenominator", nsContext, 0.0 ); 1157 // optional: <MaxScaleDenominator> 1158 double max = XMLTools.getNodeAsDouble( element, "sld:MaxScaleDenominator", nsContext, 9E99 ); 1159 1160 // optional: different Symbolizer-elements 1161 NodeList symbolizerNL = element.getChildNodes(); 1162 ArrayList<Symbolizer> symbolizerList = new ArrayList<Symbolizer>( symbolizerNL.getLength() ); 1163 1164 for ( int i = 0; i < symbolizerNL.getLength(); i++ ) { 1165 if ( symbolizerNL.item( i ) instanceof Element ) { 1166 Element symbolizerElement = (Element) symbolizerNL.item( i ); 1167 String namespace = symbolizerElement.getNamespaceURI(); 1168 1169 if ( !CommonNamespaces.SLDNS.toString().equals( namespace ) 1170 && !CommonNamespaces.SENS.toString().equals( namespace ) ) { 1171 continue; 1172 } 1173 1174 String symbolizerName = symbolizerElement.getLocalName(); 1175 1176 if ( symbolizerName.equals( "LineSymbolizer" ) ) { 1177 symbolizerList.add( createLineSymbolizer( symbolizerElement, min, max ) ); 1178 } else if ( symbolizerName.equals( "PointSymbolizer" ) ) { 1179 symbolizerList.add( createPointSymbolizer( symbolizerElement, min, max ) ); 1180 } else if ( symbolizerName.equals( "PolygonSymbolizer" ) ) { 1181 symbolizerList.add( createPolygonSymbolizer( symbolizerElement, min, max ) ); 1182 } else if ( symbolizerName.equals( "TextSymbolizer" ) ) { 1183 symbolizerList.add( createTextSymbolizer( symbolizerElement, min, max ) ); 1184 } else if ( symbolizerName.equals( "RasterSymbolizer" ) ) { 1185 symbolizerList.add( createRasterSymbolizer( symbolizerElement, min, max ) ); 1186 } 1187 } 1188 } 1189 1190 Symbolizer[] symbolizers = symbolizerList.toArray( new Symbolizer[symbolizerList.size()] ); 1191 1192 return new Rule( symbolizers, name, title, abstract_, legendGraphic, filter, isAnElseFilter, min, max ); 1193 } 1194 1195 /** 1196 * Creates a <tt>PointSymbolizer</tt>-instance according to the contents of the DOM-subtree 1197 * starting at the given 'PointSymbolizer'-<tt>Element</tt>. 1198 * <p> 1199 * 1200 * @param element 1201 * the 'PointSymbolizer'-<tt>Element</tt> 1202 * @param min 1203 * scale-constraint to be used 1204 * @param max 1205 * scale-constraint to be used 1206 * @throws XMLParsingException 1207 * if a syntactic or semantic error in the DOM-subtree is encountered 1208 * @return the constructed <tt>PointSymbolizer</tt>-instance 1209 */ 1210 private static PointSymbolizer createPointSymbolizer( Element element, double min, double max ) 1211 throws XMLParsingException { 1212 1213 // optional: <Geometry> 1214 Geometry geometry = null; 1215 Element geometryElement = XMLTools.getChildElement( "Geometry", CommonNamespaces.SLDNS, element ); 1216 1217 if ( geometryElement != null ) { 1218 geometry = createGeometry( geometryElement ); 1219 } 1220 1221 // optional: <Graphic> 1222 Graphic graphic = null; 1223 Element graphicElement = XMLTools.getChildElement( "Graphic", CommonNamespaces.SLDNS, element ); 1224 1225 if ( graphicElement != null ) { 1226 graphic = createGraphic( graphicElement ); 1227 } 1228 1229 PointSymbolizer ps = null; 1230 String respClass = XMLTools.getAttrValue( element, null, "responsibleClass", null ); 1231 if ( respClass == null ) { 1232 ps = new PointSymbolizer( graphic, geometry, min, max ); 1233 } else { 1234 ps = new PointSymbolizer( graphic, geometry, respClass, min, max ); 1235 } 1236 1237 return ps; 1238 } 1239 1240 /** 1241 * Creates a <tt>LineSymbolizer</tt>-instance according to the contents of the DOM-subtree 1242 * starting at the given 'LineSymbolizer'-<tt>Element</tt>. 1243 * <p> 1244 * 1245 * @param element 1246 * the 'LineSymbolizer'-<tt>Element</tt> 1247 * @param min 1248 * scale-constraint to be used 1249 * @param max 1250 * scale-constraint to be used 1251 * @throws XMLParsingException 1252 * if a syntactic or semantic error in the DOM-subtree is encountered 1253 * @return the constructed <tt>LineSymbolizer</tt>-instance 1254 */ 1255 private static LineSymbolizer createLineSymbolizer( Element element, double min, double max ) 1256 throws XMLParsingException { 1257 1258 // optional: <Geometry> 1259 Geometry geometry = null; 1260 Element geometryElement = XMLTools.getChildElement( "Geometry", CommonNamespaces.SLDNS, element ); 1261 1262 if ( geometryElement != null ) { 1263 geometry = createGeometry( geometryElement ); 1264 } 1265 1266 // optional: <Stroke> 1267 Stroke stroke = null; 1268 Element strokeElement = XMLTools.getChildElement( "Stroke", CommonNamespaces.SLDNS, element ); 1269 1270 if ( strokeElement != null ) { 1271 stroke = createStroke( strokeElement ); 1272 } 1273 1274 LineSymbolizer ls = null; 1275 String respClass = XMLTools.getAttrValue( element, null, "responsibleClass", null ); 1276 if ( respClass == null ) { 1277 ls = new LineSymbolizer( stroke, geometry, min, max ); 1278 } else { 1279 ls = new LineSymbolizer( stroke, geometry, respClass, min, max ); 1280 } 1281 return ls; 1282 } 1283 1284 /** 1285 * Creates a <tt>PolygonSymbolizer</tt>-instance according to the contents of the DOM-subtree 1286 * starting at the given 'PolygonSymbolizer'-<tt>Element</tt>. 1287 * <p> 1288 * 1289 * @param element 1290 * the 'PolygonSymbolizer'-<tt>Element</tt> 1291 * @param min 1292 * scale-constraint to be used 1293 * @param max 1294 * scale-constraint to be used 1295 * @throws XMLParsingException 1296 * if a syntactic or semantic error in the DOM-subtree is encountered 1297 * @return the constructed <tt>PolygonSymbolizer</tt>-instance 1298 */ 1299 private static PolygonSymbolizer createPolygonSymbolizer( Element element, double min, double max ) 1300 throws XMLParsingException { 1301 // optional: <Geometry> 1302 Geometry geometry = null; 1303 Element geometryElement = XMLTools.getChildElement( "Geometry", CommonNamespaces.SLDNS, element ); 1304 1305 if ( geometryElement != null ) { 1306 geometry = createGeometry( geometryElement ); 1307 } 1308 1309 // optional: <Fill> 1310 Fill fill = null; 1311 Element fillElement = XMLTools.getChildElement( "Fill", CommonNamespaces.SLDNS, element ); 1312 1313 if ( fillElement != null ) { 1314 fill = createFill( fillElement ); 1315 } 1316 1317 // optional: <Stroke> 1318 Stroke stroke = null; 1319 Element strokeElement = XMLTools.getChildElement( "Stroke", CommonNamespaces.SLDNS, element ); 1320 1321 if ( strokeElement != null ) { 1322 stroke = createStroke( strokeElement ); 1323 } 1324 1325 PolygonSymbolizer ps = null; 1326 String respClass = XMLTools.getAttrValue( element, null, "responsibleClass", null ); 1327 if ( respClass == null ) { 1328 ps = new PolygonSymbolizer( fill, stroke, geometry, min, max ); 1329 } else { 1330 ps = new PolygonSymbolizer( fill, stroke, geometry, respClass, min, max ); 1331 } 1332 1333 return ps; 1334 } 1335 1336 /** 1337 * Creates a <tt>Geometry</tt>-instance according to the contents of the DOM-subtree starting 1338 * at the given 'Geometry'-<tt>Element</tt>. 1339 * <p> 1340 * FIXME: Add support for 'Function'-Elements. 1341 * <p> 1342 * 1343 * @param element 1344 * the 'Geometry'-<tt>Element</tt> 1345 * @throws XMLParsingException 1346 * if a syntactic or semantic error in the DOM-subtree is encountered 1347 * @return the constructed <tt>Geometry</tt>-instance 1348 */ 1349 private static Geometry createGeometry( Element element ) 1350 throws XMLParsingException { 1351 Geometry geometry = null; 1352 1353 // required: <PropertyName> 1354 Element propertyNameElement = XMLTools.getRequiredChildElement( "PropertyName", ogcNS, element ); 1355 1356 // optional: <Function> 1357 Element functionElement = XMLTools.getChildElement( "Function", ogcNS, propertyNameElement ); 1358 1359 // just a property name exists 1360 if ( functionElement == null ) { 1361 Node node = XMLTools.getNode( propertyNameElement, "/text()", nsContext ); 1362 PropertyPath pp = OGCDocument.parsePropertyPath( (Text) node ); 1363 geometry = new Geometry( pp, null ); 1364 } else { 1365 // FIXME: 1366 // the property probably contains a wfs:Function expression 1367 } 1368 1369 return geometry; 1370 } 1371 1372 /** 1373 * Creates a <tt>Fill</tt>-instance according to the contents of the DOM-subtree starting at 1374 * the given 'Fill'-<tt>Element</tt>. 1375 * <p> 1376 * 1377 * @param element 1378 * the 'Fill'-<tt>Element</tt> 1379 * @throws XMLParsingException 1380 * if a syntactic or semantic error in the DOM-subtree is encountered 1381 * @return the constructed <tt>Fill</tt>-instance 1382 */ 1383 private static Fill createFill( Element element ) 1384 throws XMLParsingException { 1385 // optional: <GraphicFill> 1386 GraphicFill graphicFill = null; 1387 Element graphicFillElement = XMLTools.getChildElement( "GraphicFill", CommonNamespaces.SLDNS, element ); 1388 1389 if ( graphicFillElement != null ) { 1390 graphicFill = createGraphicFill( graphicFillElement ); 1391 } 1392 1393 // optional: <CssParameter>s 1394 ElementList nl = XMLTools.getChildElements( "CssParameter", CommonNamespaces.SLDNS, element ); 1395 HashMap<String, Object> cssParams = new HashMap<String, Object>( nl.getLength() ); 1396 1397 for ( int i = 0; i < nl.getLength(); i++ ) { 1398 CssParameter cssParam = createCssParameter( nl.item( i ) ); 1399 cssParams.put( cssParam.getName(), cssParam ); 1400 } 1401 1402 return new Fill( cssParams, graphicFill ); 1403 } 1404 1405 /** 1406 * Creates a <tt>LegendGraphic</tt>-instance according to the contents of the DOM-subtree 1407 * starting at the given 'LegendGraphic'-element. 1408 * <p> 1409 * 1410 * @param element 1411 * the 'LegendGraphic'-<tt>Element</tt> 1412 * @throws XMLParsingException 1413 * if a syntactic or semantic error in the DOM-subtree is encountered 1414 * @return the constructed <tt>Graphic</tt>-instance 1415 */ 1416 private static LegendGraphic createLegendGraphic( Element element ) 1417 throws XMLParsingException { 1418 // required: <Graphic> 1419 Element graphicElement = XMLTools.getRequiredChildElement( "Graphic", CommonNamespaces.SLDNS, element ); 1420 Graphic graphic = createGraphic( graphicElement ); 1421 1422 return new LegendGraphic( graphic ); 1423 } 1424 1425 /** 1426 * Creates an <tt>ExternalGraphic</tt>-instance according to the contents of the DOM-subtree 1427 * starting at the given 'ExternalGraphic'-<tt>Element</tt>. 1428 * <p> 1429 * 1430 * @param element 1431 * the 'ExternalGraphic'-<tt>Element</tt> 1432 * @throws XMLParsingException 1433 * if a syntactic or semantic error in the DOM-subtree is encountered 1434 * @return the constructed <tt>ExternalGraphic</tt>-instance 1435 */ 1436 private static ExternalGraphic createExternalGraphic( Element element ) 1437 throws XMLParsingException { 1438 // required: <OnlineResource> 1439 Element onlineResourceElement = XMLTools.getRequiredChildElement( "OnlineResource", CommonNamespaces.SLDNS, 1440 element ); 1441 1442 // required: href-Attribute (in <OnlineResource>) 1443 String href = XMLTools.getRequiredAttrValue( "href", xlnNS, onlineResourceElement ); 1444 URL url = null; 1445 try { 1446 url = sldDoc.resolve( href ); 1447 } catch ( MalformedURLException e ) { 1448 LOG.logDebug( e.getMessage(), e ); 1449 throw new XMLParsingException( "Value ('" + href + "') of attribute 'href' of " 1450 + "element 'OnlineResoure' does not denote a valid URL" ); 1451 } 1452 1453 // required: <Format> (in <OnlineResource>) 1454 String format = XMLTools.getRequiredStringValue( "Format", CommonNamespaces.SLDNS, element ); 1455 1456 return new ExternalGraphic( format, url ); 1457 } 1458 1459 /** 1460 * Creates a <tt>Mark</tt>-instance according to the contents of the DOM-subtree starting at 1461 * the given 'Mark'-<tt>Element</tt>. 1462 * <p> 1463 * 1464 * @param element 1465 * the 'Mark'-<tt>Element</tt> 1466 * @throws XMLParsingException 1467 * if a syntactic or semantic error in the DOM-subtree is encountered 1468 * @return the constructed <tt>Mark</tt>-instance 1469 */ 1470 private static Mark createMark( Element element ) 1471 throws XMLParsingException { 1472 Stroke stroke = null; 1473 Fill fill = null; 1474 1475 // optional: <WellKnownName> 1476 String wkn = XMLTools.getStringValue( "WellKnownName", CommonNamespaces.SLDNS, element, null ); 1477 1478 // optional: <Stroke> 1479 Element strokeElement = XMLTools.getChildElement( "Stroke", CommonNamespaces.SLDNS, element ); 1480 1481 if ( strokeElement != null ) { 1482 stroke = createStroke( strokeElement ); 1483 } 1484 1485 // optional: <Fill> 1486 Element fillElement = XMLTools.getChildElement( "Fill", CommonNamespaces.SLDNS, element ); 1487 1488 if ( fillElement != null ) { 1489 fill = createFill( fillElement ); 1490 } 1491 1492 return new Mark( wkn, stroke, fill ); 1493 } 1494 1495 /** 1496 * Creates a <tt>Stroke</tt>-instance according to the contents of the DOM-subtree starting 1497 * at the given 'Stroke'-<tt>Element</tt>. 1498 * <p> 1499 * 1500 * @param element 1501 * the 'Stroke'-<tt>Element</tt> 1502 * @throws XMLParsingException 1503 * if a syntactic or semantic error in the DOM-subtree is encountered 1504 * @return the constructed <tt>Stroke</tt>-instance 1505 */ 1506 private static Stroke createStroke( Element element ) 1507 throws XMLParsingException { 1508 GraphicFill gf = null; 1509 GraphicStroke gs = null; 1510 1511 // optional: <GraphicFill> 1512 Element gfElement = XMLTools.getChildElement( "GraphicFill", CommonNamespaces.SLDNS, element ); 1513 1514 if ( gfElement != null ) { 1515 gf = createGraphicFill( gfElement ); 1516 } 1517 1518 // optional: <GraphicStroke> 1519 Element gsElement = XMLTools.getChildElement( "GraphicStroke", CommonNamespaces.SLDNS, element ); 1520 1521 if ( gsElement != null ) { 1522 gs = createGraphicStroke( gsElement ); 1523 } 1524 1525 // optional: <CssParameter>s 1526 ElementList nl = XMLTools.getChildElements( "CssParameter", CommonNamespaces.SLDNS, element ); 1527 HashMap<String, Object> cssParams = new HashMap<String, Object>( nl.getLength() ); 1528 1529 for ( int i = 0; i < nl.getLength(); i++ ) { 1530 CssParameter cssParam = createCssParameter( nl.item( i ) ); 1531 cssParams.put( cssParam.getName(), cssParam ); 1532 } 1533 1534 return new Stroke( cssParams, gs, gf ); 1535 } 1536 1537 /** 1538 * Creates a <tt>GraphicFill</tt>-instance according to the contents of the DOM-subtree 1539 * starting at the given 'GraphicFill'-<tt>Element</tt>. 1540 * <p> 1541 * 1542 * @param element 1543 * the 'GraphicFill'-<tt>Element</tt> 1544 * @throws XMLParsingException 1545 * if a syntactic or semantic error in the DOM-subtree is encountered 1546 * @return the constructed <tt>GraphicFill</tt>-instance 1547 */ 1548 private static GraphicFill createGraphicFill( Element element ) 1549 throws XMLParsingException { 1550 // required: <Graphic> 1551 Element graphicElement = XMLTools.getRequiredChildElement( "Graphic", CommonNamespaces.SLDNS, element ); 1552 Graphic graphic = createGraphic( graphicElement ); 1553 1554 return new GraphicFill( graphic ); 1555 } 1556 1557 /** 1558 * Creates a <tt>GraphicStroke</tt>-instance according to the contents of the DOM-subtree 1559 * starting at the given 'GraphicStroke'-<tt>Element</tt>. 1560 * <p> 1561 * 1562 * @param element 1563 * the 'GraphicStroke'-<tt>Element</tt> 1564 * @throws XMLParsingException 1565 * if a syntactic or semantic error in the DOM-subtree is encountered 1566 * @return the constructed <tt>GraphicStroke</tt>-instance 1567 */ 1568 private static GraphicStroke createGraphicStroke( Element element ) 1569 throws XMLParsingException { 1570 // required: <Graphic> 1571 Element graphicElement = XMLTools.getRequiredChildElement( "Graphic", CommonNamespaces.SLDNS, element ); 1572 Graphic graphic = createGraphic( graphicElement ); 1573 1574 return new GraphicStroke( graphic ); 1575 } 1576 1577 /** 1578 * Creates a <tt>Graphic</tt>-instance according to the contents of the DOM-subtree starting 1579 * at the given 'Graphic'-element. 1580 * <p> 1581 * 1582 * @param element 1583 * the 'Graphic'-<tt>Element</tt> 1584 * @throws XMLParsingException 1585 * if a syntactic or semantic error in the DOM-subtree is encountered 1586 * @return the constructed <tt>Graphic</tt>-instance 1587 */ 1588 private static Graphic createGraphic( Element element ) 1589 throws XMLParsingException { 1590 1591 // optional: <Opacity> 1592 ParameterValueType opacity = null; 1593 // optional: <Size> 1594 ParameterValueType size = null; 1595 // optional: <Rotation> 1596 ParameterValueType rotation = null; 1597 1598 // optional: <ExternalGraphic>s / <Mark>s 1599 NodeList nodelist = element.getChildNodes(); 1600 ArrayList<Object> marksAndExtGraphicsList = new ArrayList<Object>(); 1601 1602 for ( int i = 0; i < nodelist.getLength(); i++ ) { 1603 if ( nodelist.item( i ) instanceof Element ) { 1604 Element child = (Element) nodelist.item( i ); 1605 String namespace = child.getNamespaceURI(); 1606 1607 if ( !CommonNamespaces.SLDNS.toString().equals( namespace ) ) { 1608 continue; 1609 } 1610 1611 String childName = child.getLocalName(); 1612 1613 if ( childName.equals( "ExternalGraphic" ) ) { 1614 marksAndExtGraphicsList.add( createExternalGraphic( child ) ); 1615 } else if ( childName.equals( "Mark" ) ) { 1616 marksAndExtGraphicsList.add( createMark( child ) ); 1617 } else if ( childName.equals( "Opacity" ) ) { 1618 opacity = createParameterValueType( child ); 1619 } else if ( childName.equals( "Size" ) ) { 1620 size = createParameterValueType( child ); 1621 } else if ( childName.equals( "Rotation" ) ) { 1622 rotation = createParameterValueType( child ); 1623 } 1624 } 1625 } 1626 1627 Object[] marksAndExtGraphics = marksAndExtGraphicsList.toArray( new Object[marksAndExtGraphicsList.size()] ); 1628 1629 return new Graphic( marksAndExtGraphics, opacity, size, rotation ); 1630 } 1631 1632 /** 1633 * Creates a <tt>CssParameter</tt>-instance according to the contents of the DOM-subtree 1634 * starting at the given 'CssParameter'-<tt>Element</tt>. 1635 * <p> 1636 * 1637 * @param element 1638 * the 'CssParamter'-<tt>Element</tt> 1639 * @throws XMLParsingException 1640 * if a syntactic or semantic error in the DOM-subtree is encountered 1641 * @return the constructed <tt>CssParameter</tt>-instance 1642 */ 1643 private static CssParameter createCssParameter( Element element ) 1644 throws XMLParsingException { 1645 // required: name-Attribute 1646 String name = XMLTools.getRequiredAttrValue( "name", null, element ); 1647 ParameterValueType pvt = createParameterValueType( element ); 1648 1649 return ( new CssParameter( name, pvt ) ); 1650 } 1651 1652 /** 1653 * <code>TresholdsBelongTo</code> enumerates values possibly belonging to 1654 * <code>ThreshholdsBelongToType</code>. 1655 * 1656 * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a> 1657 * @author last edited by: $Author: aschmitz $ 1658 * 1659 * @version $Revision: 12138 $, $Date: 2008-06-04 10:34:15 +0200 (Mi, 04 Jun 2008) $ 1660 */ 1661 public enum ThresholdsBelongTo { 1662 /** 1663 * <code>"succeeding"</code> 1664 */ 1665 SUCCEEDING, 1666 /** 1667 * <code>"preceding"</code> 1668 */ 1669 PRECEDING 1670 } 1671 1672 /** 1673 * <code>Mode</code> is the ModeType from the Symbology Encoding Schema. 1674 * 1675 * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a> 1676 * @author last edited by: $Author: aschmitz $ 1677 * 1678 * @version $Revision: 12138 $, $Date: 2008-06-04 10:34:15 +0200 (Mi, 04 Jun 2008) $ 1679 */ 1680 public enum Mode { 1681 /** 1682 * <code>"linear"</code> 1683 */ 1684 LINEAR, 1685 /** 1686 * <code>"cosine"</code> 1687 */ 1688 COSINE, 1689 /** 1690 * <code>"cubic"</code> 1691 */ 1692 CUBIC 1693 } 1694 1695 /** 1696 * <code>Method</code> is the MethodType from the Symbology encoding Schema. 1697 * 1698 * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a> 1699 * @author last edited by: $Author: aschmitz $ 1700 * 1701 * @version $Revision: 12138 $, $Date: 2008-06-04 10:34:15 +0200 (Mi, 04 Jun 2008) $ 1702 */ 1703 public enum Method { 1704 /** 1705 * <code>"numeric"</code> 1706 */ 1707 NUMERIC, 1708 /** 1709 * <code>"color"</code> 1710 */ 1711 COLOR 1712 } 1713 1714 }