001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-2007, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.styling;
017:
018: import org.geotools.data.DataStore;
019: import org.geotools.data.FeatureSource;
020: import org.geotools.factory.CommonFactoryFinder;
021: import org.geotools.feature.FeatureCollection;
022: import org.geotools.feature.FeatureType;
023: import org.opengis.filter.Filter;
024: import org.opengis.filter.expression.Expression;
025: import org.opengis.referencing.crs.CoordinateReferenceSystem;
026: import org.geotools.filter.FilterTransformer;
027: import org.geotools.gml.producer.FeatureTransformer;
028: import org.geotools.referencing.NamedIdentifier;
029: import org.geotools.xml.transform.TransformerBase;
030: import org.geotools.xml.transform.Translator;
031: import org.xml.sax.ContentHandler;
032: import org.xml.sax.SAXException;
033: import org.xml.sax.helpers.AttributesImpl;
034: import java.io.FileOutputStream;
035: import java.io.IOException;
036: import java.net.URI;
037: import java.util.HashMap;
038: import java.util.Iterator;
039: import java.util.Map;
040: import java.util.Set;
041: import java.util.Map.Entry;
042: import java.util.logging.Logger;
043:
044: /**
045: * Produces SLD to an output stream.
046: *
047: * @author Ian Schneider
048: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/styling/SLDTransformer.java $
049: */
050: public class SLDTransformer extends TransformerBase {
051: /** The logger for this package. */
052: private static final Logger LOGGER = org.geotools.util.logging.Logging
053: .getLogger("org.geotools.styling");
054:
055: static final String XLINK_NAMESPACE = "http://www.w3.org/1999/xlink";
056:
057: /**
058: * Additional namespace mappings to emit in the start element of the
059: * generated. Each entry has a URI key and an associated prefix string
060: * value.
061: */
062: final private Map uri2prefix;
063:
064: /**
065: * Construct a new instance of <code>SLDTransformer</code> with the
066: * default namespace mappings usually found in a simple Styled Layer
067: * Descriptor element.
068: */
069: public SLDTransformer() {
070: this (null);
071: }
072:
073: /**
074: * Construct a new instance of <code>SLDTransformer</code> with the
075: * additional namespace mappings contained in <code>nsBindings</code>.
076: * <p>
077: * The designated collection contains mappings of {@link URI} to associated
078: * prefix (string) to emit in the generated XML element.
079: */
080: public SLDTransformer(Map nsBindings) {
081: super ();
082: if (nsBindings == null || nsBindings.isEmpty()) {
083: uri2prefix = new HashMap();
084: } else {
085: uri2prefix = new HashMap(nsBindings.size());
086: int count = 0;
087: for (Iterator it = nsBindings.entrySet().iterator(); it
088: .hasNext();) {
089: Map.Entry e = (Entry) it.next();
090: URI uri = (URI) e.getKey();
091: String prefix = (String) e.getValue();
092: if (uri != null && prefix != null) {
093: uri2prefix.put(uri, prefix.trim());
094: count++;
095: }
096: }
097: LOGGER.info("Added [" + count
098: + "] namespace entries resulting in ["
099: + uri2prefix.size() + "] distinct entries");
100: }
101: }
102:
103: public Translator createTranslator(ContentHandler handler) {
104: Translator result = new SLDTranslator(handler);
105: // add pre-configured namespace mappings
106: if (!uri2prefix.isEmpty()) {
107: for (Iterator it = uri2prefix.entrySet().iterator(); it
108: .hasNext();) {
109: Map.Entry e = (Entry) it.next();
110: URI uri = (URI) e.getKey();
111: if (uri != null) {
112: String prefix = (String) e.getValue();
113: // FIXME handle default namespace and possible clash with
114: // one already known to the namespace-support delegate; i.e.
115: // the entry with an empty prefix
116: String uriStr = String.valueOf(uri);
117: result.getNamespaceSupport().declarePrefix(prefix,
118: uriStr);
119: }
120: }
121: }
122: return result;
123: }
124:
125: /**
126: * Currently does nothing.
127: *
128: * @param args
129: * DOCUMENT ME!
130: *
131: * @throws Exception
132: * DOCUMENT ME!
133: */
134: public static final void main(String[] args) throws Exception {
135: java.net.URL url = new java.io.File(args[0]).toURL();
136: SLDParser s = new SLDParser(CommonFactoryFinder
137: .getStyleFactory(null), url);
138: SLDTransformer transformer = new SLDTransformer();
139: transformer.setIndentation(4);
140: transformer.transform(s.readXML(), new FileOutputStream(System
141: .getProperty("java.io.tmpdir")
142: + "/junk.eraseme"));
143: }
144:
145: static class SLDTranslator extends TranslatorSupport implements
146: StyleVisitor {
147: FilterTransformer.FilterTranslator filterTranslator;
148:
149: public SLDTranslator(ContentHandler handler) {
150: super (handler, "sld", "http://www.opengis.net/sld");
151: filterTranslator = new FilterTransformer.FilterTranslator(
152: handler);
153: addNamespaceDeclarations(filterTranslator);
154: }
155:
156: void element(String element, Expression e) {
157: start(element);
158: filterTranslator.encode(e);
159: end(element);
160: }
161:
162: void element(String element, Filter f) {
163: start(element);
164: filterTranslator.encode(f);
165: end(element);
166: }
167:
168: public void visit(PointPlacement pp) {
169: start("LabelPlacement");
170: start("PointPlacement");
171: pp.getAnchorPoint().accept(this );
172: pp.getDisplacement().accept(this );
173: element("Rotation", pp.getRotation());
174: end("PointPlacement");
175: end("LabelPlacement");
176: }
177:
178: public void visit(Stroke stroke) {
179: start("Stroke");
180:
181: if (stroke.getGraphicFill() != null) {
182: start("GraphicFill");
183: stroke.getGraphicFill().accept(this );
184: end("GraphicFill");
185: }
186:
187: if (stroke.getGraphicStroke() != null) {
188: start("GraphicStroke");
189: stroke.getGraphicStroke().accept(this );
190: end("GraphicStroke");
191: }
192:
193: encodeCssParam("stroke", stroke.getColor());
194: encodeCssParam("stroke-linecap", stroke.getLineCap());
195: encodeCssParam("stroke-linejoin", stroke.getLineJoin());
196: encodeCssParam("stroke-opacity", stroke.getOpacity());
197: encodeCssParam("stroke-width", stroke.getWidth());
198: encodeCssParam("stroke-dashoffset", stroke.getDashOffset());
199:
200: float[] dash = stroke.getDashArray();
201:
202: // if (dash != null) {
203: StringBuffer sb = new StringBuffer();
204:
205: for (int i = 0; i < dash.length; i++) {
206: sb.append(dash[i] + " ");
207: }
208:
209: encodeCssParam("stroke-dasharray", sb.toString());
210:
211: // }
212: end("Stroke");
213: }
214:
215: public void visit(LinePlacement lp) {
216: start("LabelPlacement");
217: start("LinePlacement");
218: element("PerpendicularOffset", lp.getPerpendicularOffset());
219: end("LinePlacement");
220: end("LabelPlacement");
221: }
222:
223: public void visit(AnchorPoint ap) {
224: start("AnchorPoint");
225: element("AnchorPointX", ap.getAnchorPointX());
226: element("AnchorPointY", ap.getAnchorPointY());
227: end("AnchorPoint");
228: }
229:
230: public void visit(TextSymbolizer text) {
231: if (text == null) {
232: return;
233: }
234:
235: start("TextSymbolizer");
236:
237: if (text.getGeometryPropertyName() != null) {
238: encodeGeometryProperty(text.getGeometryPropertyName());
239: }
240:
241: if (text.getLabel() != null) {
242: element("Label", text.getLabel());
243: }
244:
245: if ((text.getFonts() != null)
246: && (text.getFonts().length != 0)) {
247: start("Font");
248:
249: Font[] fonts = text.getFonts();
250:
251: for (int i = 0; i < fonts.length; i++) {
252: encodeCssParam("font-family", fonts[i]
253: .getFontFamily());
254: }
255:
256: encodeCssParam("font-size", fonts[0].getFontSize());
257: encodeCssParam("font-style", fonts[0].getFontStyle());
258: encodeCssParam("font-weight", fonts[0].getFontWeight());
259: end("Font");
260: }
261:
262: if (text.getPlacement() != null) {
263: text.getPlacement().accept(this );
264: }
265:
266: if (text.getHalo() != null) {
267: text.getHalo().accept(this );
268: }
269:
270: if (text.getFill() != null) {
271: text.getFill().accept(this );
272: }
273:
274: if (text.getOptions() != null) {
275: encodeVendorOptions(text.getOptions());
276: }
277:
278: if (text.getPriority() != null) {
279: start("Priority");
280: element("PropertyName", text.getPriority());
281: end("Priority");
282: }
283:
284: end("TextSymbolizer");
285: }
286:
287: public void visit(RasterSymbolizer raster) {
288: if (raster == null) {
289: return;
290: }
291:
292: start("RasterSymbolizer");
293:
294: if (raster.getGeometryPropertyName() != null) {
295: encodeGeometryProperty(raster.getGeometryPropertyName());
296: }
297:
298: if (raster.getOpacity() != null) {
299: start("Opacity");
300: filterTranslator.encode(raster.getOpacity());
301: end("Opacity");
302: }
303:
304: if (raster.getOverlap() != null) {
305: start("OverlapBehavior");
306: filterTranslator.encode(raster.getOverlap());
307: end("OverlapBehavior");
308: }
309:
310: if (raster.getColorMap() != null) {
311: raster.getColorMap().accept(this );
312: }
313:
314: end("RasterSymbolizer");
315: }
316:
317: public void visit(ColorMap colorMap) {
318: ColorMapEntry[] mapEntries = colorMap.getColorMapEntries();
319: start("ColorMap");
320: for (int i = 0; i < mapEntries.length; i++) {
321: mapEntries[i].accept(this );
322: }
323: end("ColorMap");
324: }
325:
326: public void visit(ColorMapEntry colorEntry) {
327: if (colorEntry != null) {
328: AttributesImpl atts = new AttributesImpl();
329: atts.addAttribute("", "color", "color", "", colorEntry
330: .getColor().toString());
331: if (colorEntry.getOpacity() != null) {
332: atts.addAttribute("", "opacity", "opacity", "",
333: colorEntry.getOpacity().toString());
334: }
335: if (colorEntry.getQuantity() != null) {
336: atts.addAttribute("", "quantity", "quantity", "",
337: colorEntry.getQuantity().toString());
338: }
339: if (colorEntry.getLabel() != null) {
340: atts.addAttribute("", "label", "label", "",
341: colorEntry.getLabel());
342: }
343: element("ColorMapEntry", null, atts);
344: }
345: }
346:
347: public void visit(Symbolizer sym) {
348: try {
349: contentHandler
350: .startElement("", "!--", "!--", NULL_ATTS);
351: chars("Unidentified Symbolizer " + sym.getClass());
352: contentHandler.endElement("", "--", "--");
353: } catch (SAXException se) {
354: throw new RuntimeException(se);
355: }
356: }
357:
358: public void visit(PolygonSymbolizer poly) {
359: start("PolygonSymbolizer");
360: encodeGeometryProperty(poly.getGeometryPropertyName());
361:
362: if (poly.getFill() != null) {
363: poly.getFill().accept(this );
364: }
365:
366: if (poly.getStroke() != null) {
367: poly.getStroke().accept(this );
368: }
369:
370: end("PolygonSymbolizer");
371: }
372:
373: public void visit(ExternalGraphic exgr) {
374: start("ExternalGraphic");
375:
376: AttributesImpl atts = new AttributesImpl();
377: try {
378: atts.addAttribute(XMLNS_NAMESPACE, "xlink",
379: "xmlns:xlink", "", XLINK_NAMESPACE);
380: atts.addAttribute(XLINK_NAMESPACE, "type",
381: "xlink:type", "", "simple");
382: atts
383: .addAttribute(XLINK_NAMESPACE, "xlink",
384: "xlink:href", "", exgr.getLocation()
385: .toString());
386: } catch (java.net.MalformedURLException murle) {
387: throw new Error(
388: "SOMEONE CODED THE X LINK NAMESPACE WRONG!!");
389: }
390: element("OnlineResource", null, atts);
391:
392: element("Format", exgr.getFormat());
393:
394: end("ExternalGraphic");
395: }
396:
397: public void visit(LineSymbolizer line) {
398: start("LineSymbolizer");
399:
400: encodeGeometryProperty(line.getGeometryPropertyName());
401:
402: line.getStroke().accept(this );
403: end("LineSymbolizer");
404: }
405:
406: public void visit(Fill fill) {
407: start("Fill");
408:
409: if (fill.getGraphicFill() != null) {
410: start("GraphicFill");
411: fill.getGraphicFill().accept(this );
412: end("GraphicFill");
413: }
414:
415: encodeCssParam("fill", fill.getColor());
416: encodeCssParam("fill-opacity", fill.getOpacity());
417: end("Fill");
418: }
419:
420: public void visit(Rule rule) {
421: start("Rule");
422: if (rule.getName() != null)
423: element("Name", rule.getName());
424: if (rule.getTitle() != null)
425: element("Title", rule.getTitle());
426: if (rule.getAbstract() != null)
427: element("Abstract", rule.getAbstract());
428:
429: Graphic[] gr = rule.getLegendGraphic();
430: for (int i = 0; i < gr.length; i++) {
431: start("LegendGraphic");
432: gr[i].accept(this );
433: end("LegendGraphic");
434: }
435:
436: if (rule.getFilter() != null) {
437: filterTranslator.encode(rule.getFilter());
438: }
439:
440: if (rule.hasElseFilter()) {
441: start("ElseFilter");
442: end("ElseFilter");
443: }
444:
445: if (rule.getMinScaleDenominator() != 0.0) {
446: element("MinScaleDenominator", rule
447: .getMinScaleDenominator()
448: + "");
449: }
450:
451: if (rule.getMaxScaleDenominator() != Double.POSITIVE_INFINITY) {
452: element("MaxScaleDenominator", rule
453: .getMaxScaleDenominator()
454: + "");
455: }
456:
457: Symbolizer[] sym = rule.getSymbolizers();
458: for (int i = 0; i < sym.length; i++) {
459: sym[i].accept(this );
460: }
461:
462: end("Rule");
463: }
464:
465: public void visit(Mark mark) {
466: start("Mark");
467: if (mark.getWellKnownName() != null) {
468: element("WellKnownName", mark.getWellKnownName()
469: .toString());
470: }
471:
472: if (mark.getFill() != null) {
473: mark.getFill().accept(this );
474: }
475:
476: if (mark.getStroke() != null) {
477: mark.getStroke().accept(this );
478: }
479:
480: end("Mark");
481: }
482:
483: public void visit(PointSymbolizer ps) {
484: start("PointSymbolizer");
485:
486: encodeGeometryProperty(ps.getGeometryPropertyName());
487:
488: ps.getGraphic().accept(this );
489: end("PointSymbolizer");
490: }
491:
492: public void visit(Halo halo) {
493: start("Halo");
494: if (halo.getRadius() != null) {
495: start("Radius");
496: filterTranslator.encode(halo.getRadius());
497: end("Radius");
498: }
499: if (halo.getFill() != null) {
500: halo.getFill().accept(this );
501: }
502: end("Halo");
503: }
504:
505: public void visit(Graphic gr) {
506: start("Graphic");
507:
508: encodeGeometryProperty(gr.getGeometryPropertyName());
509:
510: Symbol[] symbols = gr.getSymbols();
511:
512: for (int i = 0; i < symbols.length; i++) {
513: symbols[i].accept(this );
514: }
515:
516: element("Opacity", gr.getOpacity());
517: element("Size", gr.getSize());
518: element("Rotation", gr.getRotation());
519:
520: end("Graphic");
521: }
522:
523: public void visit(StyledLayerDescriptor sld) {
524: AttributesImpl atts = new AttributesImpl();
525: atts.addAttribute("", "version", "version", "", "1.0.0");
526: start("StyledLayerDescriptor", atts);
527:
528: if ((sld.getName() != null) && (sld.getName().length() > 0)) {
529: element("Name", sld.getName()); //optional
530: }
531: if ((sld.getTitle() != null)
532: && (sld.getTitle().length() > 0)) {
533: element("Title", sld.getTitle()); //optional
534: }
535: if ((sld.getAbstract() != null)
536: && (sld.getAbstract().length() > 0)) {
537: element("Abstract", sld.getAbstract()); //optional
538: }
539:
540: StyledLayer[] layers = sld.getStyledLayers();
541:
542: for (int i = 0; i < layers.length; i++) {
543: if (layers[i] instanceof NamedLayer) {
544: visit((NamedLayer) layers[i]);
545: } else if (layers[i] instanceof UserLayer) {
546: visit((UserLayer) layers[i]);
547: } else {
548: throw new IllegalArgumentException("StyledLayer '"
549: + layers[i].getClass().toString()
550: + "' not found");
551: }
552: }
553:
554: end("StyledLayerDescriptor");
555: }
556:
557: public void visit(NamedLayer layer) {
558: start("NamedLayer");
559: element("Name", layer.getName());
560:
561: FeatureTypeConstraint[] lfc = layer
562: .getLayerFeatureConstraints();
563: if ((lfc != null) && lfc.length > 0) {
564: start("LayerFeatureConstraints"); //optional
565: for (int i = 0; i < lfc.length; i++) {
566: visit(lfc[i]);
567: }
568: end("LayerFeatureConstraints");
569: }
570:
571: Style[] styles = layer.getStyles();
572:
573: for (int i = 0; i < styles.length; i++) {
574: visit(styles[i]);
575: }
576:
577: end("NamedLayer");
578: }
579:
580: public void visit(UserLayer layer) {
581: start("UserLayer");
582:
583: if ((layer.getName() != null)
584: && (layer.getName().length() > 0)) {
585: element("Name", layer.getName()); //optional
586: }
587:
588: DataStore inlineFDS = layer.getInlineFeatureDatastore();
589: if (inlineFDS != null) {
590: visitInlineFeatureType(inlineFDS, layer
591: .getInlineFeatureType());
592: } else if (layer.getRemoteOWS() != null) {
593: visit(layer.getRemoteOWS());
594: }
595:
596: start("LayerFeatureConstraints"); //required
597: FeatureTypeConstraint[] lfc = layer
598: .getLayerFeatureConstraints();
599: if ((lfc != null) && lfc.length > 0) {
600: for (int i = 0; i < lfc.length; i++) {
601: visit(lfc[i]);
602: }
603: } else { //create an empty FeatureTypeConstraint, since it is required
604: start("FeatureTypeConstraint");
605: end("FeatureTypeConstraint");
606: }
607: end("LayerFeatureConstraints");
608:
609: Style[] styles = layer.getUserStyles();
610:
611: for (int i = 0; i < styles.length; i++) {
612: visit(styles[i]);
613: }
614:
615: end("UserLayer");
616: }
617:
618: private void visitInlineFeatureType(DataStore dataStore,
619: FeatureType featureType) {
620: start("InlineFeature");
621: try {
622: final String ftName = featureType.getTypeName();
623: final FeatureSource fs = dataStore
624: .getFeatureSource(ftName);
625: final FeatureCollection fc = fs.getFeatures();
626: final FeatureTransformer ftrax = new FeatureTransformer();
627: ftrax.setCollectionNamespace(null);
628: ftrax.setCollectionPrefix(null);
629: ftrax.setGmlPrefixing(true);
630: ftrax.setIndentation(2);
631: final CoordinateReferenceSystem crs = featureType
632: .getDefaultGeometry().getCoordinateSystem();
633: String srsName = null;
634: if (crs == null) {
635: LOGGER.warning("Null CRS in feature type named ["
636: + ftName + "]. Ignore CRS");
637: } else {
638: // assume the first named identifier of this CRS is its
639: // fully
640: // qualified code; e.g. authoriy and SRID
641: Set ids = crs.getIdentifiers();
642: if (ids == null || ids.isEmpty()) {
643: LOGGER
644: .warning("Null or empty set of named identifiers "
645: + "in CRS ["
646: + crs
647: + "] of feature type named ["
648: + ftName + "]. Ignore CRS");
649: } else {
650: for (Iterator it = ids.iterator(); it.hasNext();) {
651: NamedIdentifier id = (NamedIdentifier) ids
652: .iterator().next();
653: if (id != null) {
654: srsName = String.valueOf(id);
655: break;
656: }
657: }
658: }
659: }
660: if (srsName != null) {
661: // Some Server implementations using older versions of this
662: // library barf on a fully qualified CRS name with messages
663: // like : "couldnt decode SRS - EPSG:EPSG:4326. currently
664: // only supporting EPSG #"; looks like they only needs the
665: // SRID. adjust
666: final int ndx = srsName.indexOf(':');
667: if (ndx > 0) {
668: LOGGER.info("Reducing CRS name [" + srsName
669: + "] to its SRID");
670: srsName = srsName.substring(ndx + 1).trim();
671: }
672: ftrax.setSrsName(srsName);
673: }
674: final String defaultNS = this .getDefaultNamespace();
675: ftrax.getFeatureTypeNamespaces()
676: .declareDefaultNamespace("", defaultNS);
677: final URI nsURI = featureType.getNamespace();
678: if (nsURI == null) {
679: LOGGER
680: .info("Null namespace URI in feature type named ["
681: + ftName
682: + "]. Ignore namespace in features");
683: } else {
684: // find the URI's prefix mapping in this namespace support
685: // delegate and use it; otherwise ignore it
686: final String ns = String.valueOf(nsURI);
687: final String prefix = this .nsSupport.getPrefix(ns);
688: if (prefix != null)
689: ftrax.getFeatureTypeNamespaces()
690: .declareNamespace(featureType, prefix,
691: ns);
692: }
693: final Translator t = ftrax
694: .createTranslator(this .contentHandler);
695: t.encode(fc);
696: } catch (IOException ignored) {
697: }
698: end("InlineFeature");
699: }
700:
701: public void visit(RemoteOWS remoteOWS) {
702: start("RemoteOWS");
703: element("Service", remoteOWS.getService());
704: element("OnlineResource", remoteOWS.getOnlineResource());
705: end("RemoteOWS");
706: }
707:
708: public void visit(FeatureTypeConstraint ftc) {
709: start("FeatureTypeConstraint");
710:
711: if (ftc != null) {
712: element("FeatureTypeName", ftc.getFeatureTypeName());
713: visit(ftc.getFilter());
714:
715: Extent[] extent = ftc.getExtents();
716:
717: for (int i = 0; i < extent.length; i++) {
718: visit(extent[i]);
719: }
720: }
721:
722: end("FeatureTypeConstraint");
723: }
724:
725: public void visit(Extent extent) {
726: start("Extent");
727: element("Name", extent.getName());
728: element("Value", extent.getValue());
729: end("Extent");
730: }
731:
732: public void visit(Filter filter) {
733: // TODO: implement this visitor
734: }
735:
736: public void visit(Style style) {
737: if (style instanceof NamedStyle) {
738: start("NamedStyle");
739: element("Name", style.getName());
740: end("NamedStyle");
741: } else {
742: start("UserStyle");
743: element("Name", style.getName());
744: element("Title", style.getTitle());
745: element("Abstract", style.getAbstract());
746: FeatureTypeStyle[] fts = style.getFeatureTypeStyles();
747: for (int i = 0; i < fts.length; i++) {
748: visit(fts[i]);
749: }
750: end("UserStyle");
751: }
752: }
753:
754: public void visit(FeatureTypeStyle fts) {
755: start("FeatureTypeStyle");
756:
757: if ((fts.getName() != null) && (fts.getName().length() > 0)) {
758: element("Name", fts.getName());
759: }
760:
761: if ((fts.getTitle() != null)
762: && (fts.getTitle().length() > 0)) {
763: element("Title", fts.getTitle());
764: }
765:
766: if ((fts.getAbstract() != null)
767: && (fts.getAbstract().length() > 0)) {
768: element("Abstract", fts.getAbstract());
769: }
770:
771: if ((fts.getFeatureTypeName() != null)
772: && (fts.getFeatureTypeName().length() > 0)) {
773: element("FeatureTypeName", fts.getFeatureTypeName());
774: }
775:
776: String[] sti = fts.getSemanticTypeIdentifiers();
777:
778: for (int i = 0; i < sti.length; i++) {
779: element("SemanticTypeIdentifier", sti[i]);
780: }
781:
782: Rule[] rules = fts.getRules();
783:
784: for (int i = 0; i < rules.length; i++) {
785: rules[i].accept(this );
786: }
787:
788: end("FeatureTypeStyle");
789: }
790:
791: public void visit(Displacement dis) {
792: start("Displacement");
793: element("DisplacementX", dis.getDisplacementX());
794: element("DisplacementY", dis.getDisplacementY());
795: end("Displacement");
796: }
797:
798: void encodeGeometryProperty(String name) {
799: if ((name == null) || (name.trim().length() == 0)) {
800: return;
801: }
802:
803: start("Geometry");
804: element("PropertyName", name);
805: end("Geometry");
806: }
807:
808: void encodeCssParam(String name, Expression expression) {
809: if (expression == null) {
810: return; // protect ourselves from things like a null Stroke Color
811: }
812:
813: AttributesImpl atts = new AttributesImpl();
814: atts.addAttribute("", "name", "name", "", name);
815: start("CssParameter", atts);
816: filterTranslator.encode(expression);
817: end("CssParameter");
818: }
819:
820: void encodeCssParam(String name, String expression) {
821: if (expression.length() == 0) {
822: return;
823: }
824:
825: AttributesImpl atts = new AttributesImpl();
826: atts.addAttribute("", "name", "name", "", name);
827: start("CssParameter", atts);
828: chars(expression);
829: end("CssParameter");
830: }
831:
832: void encodeVendorOptions(Map options) {
833: if (options != null) {
834: Iterator it = options.keySet().iterator();
835: while (it.hasNext()) {
836: String key = (String) it.next();
837: String value = (String) options.get(key);
838: encodeVendorOption(key, value);
839: }
840: }
841: }
842:
843: void encodeVendorOption(String key, String value) {
844: AttributesImpl atts = new AttributesImpl();
845: atts.addAttribute("", "name", "name", "", key);
846: start("VendorOption", atts);
847: chars(value);
848: end("VendorOption");
849: }
850:
851: public void encode(Style[] styles) {
852: try {
853: contentHandler.startDocument();
854:
855: start("StyledLayerDescriptor", NULL_ATTS);
856: start("NamedLayer", NULL_ATTS); //this is correct?
857:
858: for (int i = 0, ii = styles.length; i < ii; i++) {
859: styles[i].accept(this );
860: }
861:
862: end("NamedLayer");
863: end("StyledLayerDescriptor");
864:
865: contentHandler.endDocument();
866: } catch (SAXException se) {
867: throw new RuntimeException(se);
868: }
869: }
870:
871: public void encode(StyledLayerDescriptor sld) {
872: try {
873: contentHandler.startDocument();
874: sld.accept(this );
875: contentHandler.endDocument();
876: } catch (SAXException se) {
877: throw new RuntimeException(se);
878: }
879: }
880:
881: public void encode(Object o) throws IllegalArgumentException {
882: if (o instanceof StyledLayerDescriptor) {
883: encode((StyledLayerDescriptor) o);
884: } else if (o instanceof Style[]) {
885: encode((Style[]) o);
886: } else {
887: Class c = o.getClass();
888:
889: try {
890: java.lang.reflect.Method m = c.getMethod("accept",
891: new Class[] { StyleVisitor.class });
892: m.invoke(o, new Object[] { this });
893: } catch (NoSuchMethodException nsme) {
894: throw new IllegalArgumentException("Cannot encode "
895: + o);
896: } catch (Exception e) {
897: throw new RuntimeException(
898: "Internal transformation exception", e);
899: }
900: }
901: }
902: }
903: }
|