2

I've been able to export features as KML using GeoTools. However, I would like to insert a name attribute at the top level (e.g. Document, though a Folder would be fine too). (Example of what I'd like at the end.)

This is what I am getting so far:

<?xml version="1.0" encoding="UTF-8"?>
<kml:kml xmlns:xs="http://www.w3.org/2001/XMLSchema"
         xmlns:xal="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0"
         xmlns:kml="http://www.opengis.net/kml/2.2"
         xmlns:atom="http://www.w3.org/2005/Atom">
    <kml:Document id="area-418e1090-6ca8-4e34-a563-9c36db53cb35">
        <!-- would like "name" here -->
        <kml:Placemark id="shape-1">
            <kml:ExtendedData/>
            <kml:Polygon>
                <kml:outerBoundaryIs>
                    <kml:LinearRing>
                        <kml:coordinates>0.0,0.0 0.0,20.0 20.0,20.0 20.0,0.0 0.0,0.0</kml:coordinates>
                    </kml:LinearRing>
                </kml:outerBoundaryIs>
            </kml:Polygon>
        </kml:Placemark>
        <kml:Placemark id="shape-2">
            ... et cetera

        </kml:Placemark>
    </kml:Document>
</kml:kml>

The code for that I've scraped together from a bunch of examples, it boils down to this:

ArrayList<SimpleFeature> list = new ArrayList<>();
addShapes(entity, list);

DefaultFeatureCollection featureCollection = new DefaultFeatureCollection(id("area", entity.getUuid()), null);
featureCollection.addAll(list);

OutputStream outputStream = httpServletResponse.getOutputStream();
encoder.encode(featureCollection, KML.kml, outputStream);

And:

private void addShapes(AbstractAreaEntity entity, ArrayList<SimpleFeature> list) {
    List<Geometry> shapes = entity.getShapes();
    for (int i = 0; i < shapes.size(); i++) {
        Geometry geometry = shapes.get(i);
        list.add(new SimpleFeatureImpl(singletonList(geometry), shapeType, new FeatureIdImpl(id("shape", i + 1))));
    }
}

This is what I would like:

<?xml version="1.0" encoding="UTF-8"?>
<kml:kml xmlns:xs=...>
    <kml:Document id="area-418e1090-6ca8-4e34-a563-9c36db53cb35">
        <kml:name>My Document With Placemarks</kml:name> <!-- this! -->
        <kml:Placemark id="shape-1">
            ... et cetera

        </kml:Placemark>
    </kml:Document>
</kml:kml>

It appears that Encoder.encode only works with a FeatureCollection implementation, and it does not seem I can set properties or attributes on it (like name).

0

Okay, here's a "solution" since I could not dwel on this any longer. (Not really a solution, it's more a workaround.) If there's anyone with a real solution, I am still hoping to swap it out.

Updated the code that calls the encoder:

OutputStream outputStream = httpServletResponse.getOutputStream();
// this can be restored once there's a solution for this: https://gis.stackexchange.com/questions/328675
// also see the comment in the class NameInsertingDataWriter's source file
//encoder.encode(featureCollection, KML.kml, outputStream);
encoder.encode(featureCollection, KML.kml, new NameInsertingDataWriter(outputStream, entity.getName()));

The encoder is now given an implementation of org.xml.sax.ContentHandler (instead of the OutputStream directly); delegating to the following:

import com.sun.xml.bind.marshaller.DataWriter;
import org.geotools.feature.FeatureCollection;
import org.geotools.xsd.Encoder;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import javax.xml.namespace.QName;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

/**
 * Where {@link Encoder#encode(Object, QName, OutputStream)} takes an {@link Object} as its first argument, seemingly
 * this needs to be a {@link FeatureCollection}, which seems to have no way to set a {@code name} attribute.
 * <p>
 * See the question here: https://gis.stackexchange.com/questions/328675
 * <p>
 * This implements an alternative, that inserts the {@code <name/>} element, as soon as it sees the {@code Document}
 * element.
 */
public class NameInsertingDataWriter extends DataWriter {
    private static final String DOCUMENT_ELEMENT = "Document";

    private static final String LOCAL_NAME = "name";

    private static final String Q_NAME = "kml:name";

    private String name;

    public NameInsertingDataWriter(OutputStream outputStream, String name) {
        super(new OutputStreamWriter(outputStream), "UTF-8");
        this.name = name;
        setIndentStep("  ");
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
        super.startElement(uri, localName, qName, atts);

        if (DOCUMENT_ELEMENT.equals(localName)) {
            insertNameElement(uri);
        }
    }

    private void insertNameElement(String uri) throws SAXException {
        startElement(uri, LOCAL_NAME, Q_NAME, new AttributesImpl());
        characters(name);
        endElement(uri, LOCAL_NAME, Q_NAME);
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.