diff --git a/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLFeatureUtil.java b/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLFeatureUtil.java index a3eb0221a92..bf530cf638f 100644 --- a/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLFeatureUtil.java +++ b/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLFeatureUtil.java @@ -9,6 +9,7 @@ import static org.geoserver.mapml.MapMLConstants.MAPML_SKIP_STYLES_FO; import static org.geoserver.mapml.template.MapMLMapTemplate.MAPML_FEATURE_FTL; import static org.geoserver.mapml.template.MapMLMapTemplate.MAPML_FEATURE_HEAD_FTL; +import static org.geoserver.mapml.template.MapMLMapTemplate.MapMLFeatureWrapper.COORDINATES_BLANK; import freemarker.template.TemplateNotFoundException; import java.io.IOException; @@ -23,6 +24,7 @@ import java.util.StringJoiner; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; import javax.xml.bind.JAXBException; import org.geoserver.catalog.LayerInfo; import org.geoserver.catalog.MetadataMap; @@ -32,11 +34,14 @@ import org.geoserver.mapml.tcrs.TiledCRSParams; import org.geoserver.mapml.template.MapMLMapTemplate; import org.geoserver.mapml.xml.BodyContent; +import org.geoserver.mapml.xml.Coordinates; import org.geoserver.mapml.xml.Feature; import org.geoserver.mapml.xml.HeadContent; +import org.geoserver.mapml.xml.LineString; import org.geoserver.mapml.xml.Link; import org.geoserver.mapml.xml.Mapml; import org.geoserver.mapml.xml.Meta; +import org.geoserver.mapml.xml.Point; import org.geoserver.mapml.xml.ProjType; import org.geoserver.mapml.xml.RelType; import org.geoserver.ows.Request; @@ -223,7 +228,11 @@ private static Optional getInterpolatedFromTemplate( SimpleFeatureCollection fc, SimpleFeature feature) { try { String templateOutput = mapMLMapTemplate.features(fc.getSchema(), feature); - return Optional.of(encoder.decode(new StringReader(templateOutput))); + Mapml out = encoder.decode(new StringReader(templateOutput)); + if (out != null) { + replaceSpacePlaceholder(out.getBody().getFeatures()); + } + return Optional.of(out); } catch (IOException e) { LOGGER.info( "Error unmarshalling template output for MapML features " @@ -232,6 +241,41 @@ private static Optional getInterpolatedFromTemplate( } } + private static void replaceSpacePlaceholder(List features) { + for (Feature feature : features) { + if (feature.getGeometry() != null) { + if (feature.getGeometry().getGeometryContent().getValue() instanceof Point) { + Point point = (Point) feature.getGeometry().getGeometryContent().getValue(); + point.getCoordinates().replaceAll(c -> c.replace(COORDINATES_BLANK, " ")); + } else if (feature.getGeometry().getGeometryContent().getValue() + instanceof LineString) { + LineString lineString = + (LineString) feature.getGeometry().getGeometryContent().getValue(); + lineString.getCoordinates().replaceAll(c -> c.replace(COORDINATES_BLANK, " ")); + } else if (feature.getGeometry().getGeometryContent().getValue() + instanceof org.geoserver.mapml.xml.MultiLineString) { + org.geoserver.mapml.xml.MultiLineString multiLineString = + (org.geoserver.mapml.xml.MultiLineString) + feature.getGeometry().getGeometryContent().getValue(); + multiLineString + .getTwoOrMoreCoordinatePairs() + .replaceAll( + c -> { + c.getValue() + .replaceAll(f -> f.replace(COORDINATES_BLANK, " ")); + return c; + }); + } else if (feature.getGeometry().getGeometryContent().getValue() + instanceof org.geoserver.mapml.xml.MultiPoint) { + org.geoserver.mapml.xml.MultiPoint multiPoint = + (org.geoserver.mapml.xml.MultiPoint) + feature.getGeometry().getGeometryContent().getValue(); + multiPoint.getCoordinates().replaceAll(c -> c.replace(COORDINATES_BLANK, " ")); + } + } + } + } + /** * Append the CSS style from the template to the feature * diff --git a/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLGenerator.java b/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLGenerator.java index 0a12377dcbc..77afa27f6e5 100644 --- a/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLGenerator.java +++ b/src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLGenerator.java @@ -407,7 +407,7 @@ private org.geoserver.mapml.xml.MultiPolygon buildMultiPolygon(MultiPolygon mpg) private org.geoserver.mapml.xml.MultiLineString buildMultiLineString(MultiLineString ml) { org.geoserver.mapml.xml.MultiLineString multiLine = new org.geoserver.mapml.xml.MultiLineString(); - List>> coordLists = multiLine.getTwoOrMoreCoordinatePairs(); + List>> coordLists = multiLine.getTwoOrMoreCoordinatePairs(); for (int i = 0; i < ml.getNumGeometries(); i++) { coordLists.add( factory.createMultiLineStringCoordinates( @@ -424,7 +424,7 @@ private org.geoserver.mapml.xml.MultiLineString buildMultiLineString(MultiLineSt */ private org.geoserver.mapml.xml.LineString buildLineString(LineString l) { org.geoserver.mapml.xml.LineString lineString = new org.geoserver.mapml.xml.LineString(); - List lsCoords = lineString.getCoordinates(); + List lsCoords = lineString.getCoordinates(); buildCoordinates(l.getCoordinateSequence(), lsCoords); return lineString; } @@ -435,7 +435,7 @@ private org.geoserver.mapml.xml.LineString buildLineString(LineString l) { */ private org.geoserver.mapml.xml.MultiPoint buildMultiPoint(MultiPoint mp) { org.geoserver.mapml.xml.MultiPoint multiPoint = new org.geoserver.mapml.xml.MultiPoint(); - List mpCoords = multiPoint.getCoordinates(); + List mpCoords = multiPoint.getCoordinates(); buildCoordinates(new CoordinateArraySequence(mp.getCoordinates()), mpCoords); return multiPoint; } @@ -447,11 +447,7 @@ private org.geoserver.mapml.xml.MultiPoint buildMultiPoint(MultiPoint mp) { private org.geoserver.mapml.xml.Point buildPoint(Point p) { org.geoserver.mapml.xml.Point point = new org.geoserver.mapml.xml.Point(); point.getCoordinates() - .add( - new Coordinates( - this.formatter.format(p.getX()) - + SPACE - + this.formatter.format(p.getY()))); + .add(this.formatter.format(p.getX()) + SPACE + this.formatter.format(p.getY())); return point; } @@ -512,7 +508,7 @@ private Object buildTaggedCoordinateSequence(TaggedPolygon.TaggedCoordinateSeque } else { return new Span( "bbox", - buildCoordinatesFromStrings( + buildCoordinates( new CoordinateArraySequence( cs.getCoordinates().toArray(n -> new Coordinate[n])), null)); @@ -524,8 +520,7 @@ private Object buildTaggedCoordinateSequence(TaggedPolygon.TaggedCoordinateSeque * @param coordList a list of coordinate strings to add to * @return */ - private List buildCoordinatesFromStrings( - CoordinateSequence cs, List coordList) { + private List buildCoordinates(CoordinateSequence cs, List coordList) { if (coordList == null) { coordList = new ArrayList<>(cs.size()); } @@ -536,25 +531,6 @@ private List buildCoordinatesFromStrings( return coordList; } - /** - * @param cs a JTS CoordinateSequence - * @param coordList a list of coordinate strings to add to - * @return - */ - private List buildCoordinates(CoordinateSequence cs, List coordList) { - if (coordList == null) { - coordList = new ArrayList<>(cs.size()); - } - for (int i = 0; i < cs.size(); i++) { - coordList.add( - new Coordinates( - this.formatter.format(cs.getX(i)) - + SPACE - + this.formatter.format(cs.getY(i)))); - } - return coordList; - } - /** * Builds a space separated representation of the coordinate sequence * @@ -583,7 +559,9 @@ private String buildCoordinates(List cs) { return joiner.toString(); } - /** @param numDecimals */ + /** + * @param numDecimals + */ public void setNumDecimals(int numDecimals) { // make a copy of relevant object state boolean fd = this.formatter.isForcedDecimal(); @@ -595,12 +573,16 @@ public void setNumDecimals(int numDecimals) { this.formatter.setPadWithZeros(pad); } - /** @param forcedDecimal */ + /** + * @param forcedDecimal + */ public void setForcedDecimal(boolean forcedDecimal) { this.formatter.setForcedDecimal(forcedDecimal); } - /** @param padWithZeros */ + /** + * @param padWithZeros + */ public void setPadWithZeros(boolean padWithZeros) { this.formatter.setPadWithZeros(padWithZeros); } diff --git a/src/extension/mapml/src/main/java/org/geoserver/mapml/template/MapMLMapTemplate.java b/src/extension/mapml/src/main/java/org/geoserver/mapml/template/MapMLMapTemplate.java index cbb91beb4d7..0cafbc82cec 100644 --- a/src/extension/mapml/src/main/java/org/geoserver/mapml/template/MapMLMapTemplate.java +++ b/src/extension/mapml/src/main/java/org/geoserver/mapml/template/MapMLMapTemplate.java @@ -5,6 +5,7 @@ package org.geoserver.mapml.template; import freemarker.template.Configuration; +import freemarker.template.SimpleHash; import freemarker.template.Template; import freemarker.template.TemplateException; import java.io.CharArrayWriter; @@ -23,6 +24,7 @@ import org.geoserver.template.GeoServerTemplateLoader; import org.geoserver.template.TemplateUtils; import org.geoserver.wms.featureinfo.FeatureTemplate; +import org.geotools.api.feature.ComplexAttribute; import org.geotools.api.feature.Feature; import org.geotools.api.feature.simple.SimpleFeature; import org.geotools.api.feature.simple.SimpleFeatureType; @@ -41,7 +43,7 @@ public class MapMLMapTemplate { templateConfig.setLocale(Locale.US); templateConfig.setNumberFormat("0.###########"); - templateConfig.setObjectWrapper(new FeatureWrapper(FC_FACTORY)); + templateConfig.setObjectWrapper(new MapMLFeatureWrapper(FC_FACTORY)); // encoding templateConfig.setDefaultEncoding("UTF-8"); @@ -290,4 +292,19 @@ public boolean equals(Object obj) { return true; } } + + public static class MapMLFeatureWrapper extends FeatureWrapper { + public static final String COORDINATES_BLANK = "MAPML_COORDINATES_BLANK"; + + public MapMLFeatureWrapper(DirectTemplateFeatureCollectionFactory factory) { + super(factory); + } + + @Override + protected SimpleHash buildComplex(ComplexAttribute att) { + SimpleHash hash = super.buildComplex(att); + hash.put("space", COORDINATES_BLANK); + return hash; + } + } } diff --git a/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/LineString.java b/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/LineString.java index 8e3e74f90f9..3733fd225b7 100644 --- a/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/LineString.java +++ b/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/LineString.java @@ -42,7 +42,7 @@ public class LineString { required = true, name = "map-coordinates", namespace = "http://www.w3.org/1999/xhtml") - protected List coordinates; + protected List coordinates; /** * Gets the value of the coordinates property. @@ -61,7 +61,7 @@ public class LineString { * * @return list of coordinates elements */ - public List getCoordinates() { + public List getCoordinates() { if (coordinates == null) { coordinates = new ArrayList<>(); } diff --git a/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/MultiLineString.java b/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/MultiLineString.java index ff6ed6b8f6a..0dd6ea40093 100644 --- a/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/MultiLineString.java +++ b/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/MultiLineString.java @@ -41,7 +41,7 @@ public class MultiLineString { name = "map-coordinates", type = JAXBElement.class, namespace = "http://www.w3.org/1999/xhtml") - protected List>> twoOrMoreCoordinatePairs; + protected List>> twoOrMoreCoordinatePairs; /** * Gets the value of the twoOrMoreCoordinatePairs property. @@ -61,7 +61,7 @@ public class MultiLineString { * * @return two or more coordinate pairs */ - public List>> getTwoOrMoreCoordinatePairs() { + public List>> getTwoOrMoreCoordinatePairs() { if (twoOrMoreCoordinatePairs == null) { twoOrMoreCoordinatePairs = new ArrayList<>(); } diff --git a/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/MultiPoint.java b/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/MultiPoint.java index b1136217657..b4b09fc1a3e 100644 --- a/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/MultiPoint.java +++ b/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/MultiPoint.java @@ -42,7 +42,7 @@ public class MultiPoint { required = true, name = "map-coordinates", namespace = "http://www.w3.org/1999/xhtml") - protected List coordinates; + protected List coordinates; /** * Gets the value of the map-coordinates property. Exception Description: The property or field @@ -63,7 +63,7 @@ public class MultiPoint { * * @return list of coordinates strings */ - public List getCoordinates() { + public List getCoordinates() { if (coordinates == null) { coordinates = new ArrayList<>(); } diff --git a/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/ObjectFactory.java b/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/ObjectFactory.java index 39b95a8584b..1918d038406 100644 --- a/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/ObjectFactory.java +++ b/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/ObjectFactory.java @@ -339,12 +339,11 @@ public JAXBElement createPolygonCoordinates(List value) { namespace = "http://www.w3.org/1999/xhtml", name = "map-coordinates", scope = MultiLineString.class) - public JAXBElement> createMultiLineStringCoordinates( - List value) { + public JAXBElement> createMultiLineStringCoordinates(List value) { return new JAXBElement<>( _MultiPointCoordinates_QNAME, ((Class) List.class), MultiLineString.class, - ((List) value)); + ((List) value)); } } diff --git a/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/Point.java b/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/Point.java index 2f82b0974ef..adcdf04f7ad 100644 --- a/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/Point.java +++ b/src/extension/mapml/src/main/java/org/geoserver/mapml/xml/Point.java @@ -42,7 +42,7 @@ public class Point { required = true, name = "map-coordinates", namespace = "http://www.w3.org/1999/xhtml") - protected List coordinates; + protected List coordinates; /** * Gets the value of the coordinates property. @@ -61,7 +61,7 @@ public class Point { * * @return list of coordinates strings */ - public List getCoordinates() { + public List getCoordinates() { if (coordinates == null) { coordinates = new ArrayList<>(); } diff --git a/src/extension/mapml/src/test/java/org/geoserver/mapml/MapMLWMSFeatureTest.java b/src/extension/mapml/src/test/java/org/geoserver/mapml/MapMLWMSFeatureTest.java index 9054a27aa0b..f90d6e4e40e 100644 --- a/src/extension/mapml/src/test/java/org/geoserver/mapml/MapMLWMSFeatureTest.java +++ b/src/extension/mapml/src/test/java/org/geoserver/mapml/MapMLWMSFeatureTest.java @@ -236,6 +236,7 @@ public void testCoordinateSimplification() throws Exception { li.getResource().getMetadata().put(MAPML_USE_FEATURES, true); li.getResource().getMetadata().put(MAPML_USE_TILES, false); cat.save(li); + String layerId = getLayerId(MockData.ROAD_SEGMENTS); // test with a small bbox, that should still lead to a geometric simplification Mapml mapml = @@ -366,7 +367,7 @@ public void testMapMLFeaturePointHasClass() throws Exception { + " " + " " + " <#list gattribute.rawValue.coordinates as coord>" - + " <#if coord?index == 0>]]>${coord.x} ${coord.y}]]><#else>${coord.x} ${coord.y}" + + " <#if coord?index == 0>]]>${coord.x}${space}${coord.y}]]><#else>${coord.x}${space}${coord.y}" + " " + " \n" + " \n" @@ -390,8 +391,8 @@ public void testMapMLFeaturePointHasClass() throws Exception { .getFeatures() .get(0); // get the second feature, which has a class Point featurePoint = (Point) feature2.getGeometry().getGeometryContent().getValue(); - String coords = featurePoint.getCoordinates().get(0).getCoordinates().get(0).toString(); - assertTrue(coords.contains("")); + String coords = featurePoint.getCoordinates().get(1); + assertTrue(coords.contains("class=\"desired\">")); } finally { if (template != null) { template.delete(); @@ -422,7 +423,7 @@ public void testMapMLFeatureLineHasClass() throws Exception { + "\n" + " <#list attributes as attribute>\n" + " <#if attribute.isGeometry>\n" - + " <#list attribute.rawValue.coordinates as coord><#if coord?index == 3> ]]>${coord.x} ${coord.y}<#elseif coord?index == 4> ${coord.x} ${coord.y}]]><#else> ${coord.x} ${coord.y}\n" + + " <#list attribute.rawValue.coordinates as coord><#if coord?index == 3>${space}]]>${coord.x}${space}${coord.y}<#elseif coord?index == 4>${coord.x}${space}${coord.y}]]><#else>${space}${coord.x}${space}${coord.y}\n" + " \n" + " \n" + "\n" @@ -444,8 +445,9 @@ public void testMapMLFeatureLineHasClass() throws Exception { .get(0); // get the second feature, which has a class LineString featureLine = (LineString) feature2.getGeometry().getGeometryContent().getValue(); - String coords = featureLine.getCoordinates().get(0).getCoordinates().get(0).toString(); - assertTrue(coords.contains("")); + String coords = featureLine.getCoordinates().get(7); + assertTrue(coords.contains("class=\"desired\">")); + template.delete(); } finally { if (template != null) { template.delete();