All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.micromata.opengis.kml.v_2_2_0.Kml Maven / Gradle / Ivy

Go to download

This is JavaAPIforKMml, Micromata's library for use with applications that want to parse, generate and operate on KML. It is an implementation of the OGC KML 2.2 standard. It is written entirely in Java and makes heavy use of JAXB.

There is a newer version: 3.0.4
Show newest version

package de.micromata.opengis.kml.v_2_2_0;

import de.micromata.opengis.kml.v_2_2_0.gx.Tour;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.Unmarshaller;
import jakarta.xml.bind.annotation.*;
import org.jetbrains.annotations.NotNull;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.sax.SAXSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;


/**
 * {@code }
 * 

* {@code ... * } *

*

* A basic {@code } element contains 0 or 1 Feature and 0 or 1 NetworkLinkControl: *

*

* The {@code } element may also include the namespace for any external XML schemas that * are referenced within the file. *

*

* The root element of a KML file. This element is required. It follows the xml declaration * at the beginning of the file. The hint attribute is used as a signal to Google Earth * to display the file as celestial data. *

* * Syntax: *
<kml xmlns="http://www.opengis.net/kml/2.2" hint="target=sky"> ... </kml>
* * * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "KmlType", propOrder = { "networkLinkControl", "feature", "kmlSimpleExtension", "kmlObjectExtension" }) @XmlRootElement(name = "kml", namespace = "http://www.opengis.net/kml/2.2") public class Kml implements Cloneable { /** * {@code } *

* Controls the behavior of files fetched by a NetworkLink. *

* * Syntax: *
<NetworkLinkControl>
     *   <minRefreshPeriod>0</minRefreshPeriod>           <!-- float -->
     *   <maxSessionLength>-1</maxSessionLength>          <!-- float --> 
     *   <cookie>...</cookie>                             <!-- string -->                             
     *   <message>...</message>                           <!-- string -->
     *   <linkName>...</linkName>                         <!-- string -->                          
     *   <linkDescription>...</linkDescription>           <!-- string -->              
     *   <linkSnippet maxLines="2">...</linkSnippet>      <!-- string -->                      
     *   <expires>...</expires>                           <!-- kml:dateTime -->
     *   <Update>...</Update>                             <!-- Change,Create,Delete -->
     *   <AbstractView>...</AbstractView>                 <!-- LookAt or Camera -->
     * </NetworkLinkControl>
* * See Also: * NetworkLink * Update * * * */ @XmlElement(name = "NetworkLinkControl") protected NetworkLinkControl networkLinkControl; /** * {@code } *

* This is an abstract element and cannot be used directly in a KML file. The following * diagram shows how some of a Feature's elements appear in Google Earth. *

* * Syntax: *
<!-- abstract element; do not create -->
     * <!-- Feature id="ID" -->                <!-- Document,Folder,
     *                                              NetworkLink,Placemark,
     *                                              GroundOverlay,PhotoOverlay,ScreenOverlay -->
     *   <name>...</name>                      <!-- string -->
     *   <visibility>1</visibility>            <!-- boolean -->
     *   <open>0</open>                        <!-- boolean -->
     *   <atom:author>...<atom:author>         <!-- xmlns:atom -->
     *   <atom:link>...</atom:link>            <!-- xmlns:atom -->
     *   <address>...</address>                <!-- string -->
     *   <xal:AddressDetails>...</xal:AddressDetails>  <!-- xmlns:xal -->
<phoneNumber>...</phoneNumber> <!-- string -->
<Snippet maxLines="2">...</Snippet> <!-- string --> * <description>...</description> <!-- string --> * <AbstractView>...</AbstractView> <!-- Camera or LookAt --> * <TimePrimitive>...</TimePrimitive> <!-- TimeStamp or TimeSpan --> * <styleUrl>...</styleUrl> <!-- anyURI --> * <StyleSelector>...</StyleSelector> * <Region>...</Region> * <Metadata>...</Metadata> <!-- deprecated in KML 2.2 --> * <ExtendedData>...</ExtendedData> <!-- new in KML 2.2 -->
<-- /Feature -->
* * Extends: * * * Extended By: * * * * * * * * */ @XmlElementRef(name = "AbstractFeatureGroup", namespace = "http://www.opengis.net/kml/2.2", required = false) protected Feature feature; @XmlElement(name = "KmlSimpleExtensionGroup") @XmlSchemaType(name = "anySimpleType") protected List kmlSimpleExtension; /** * {@code } *

* This is an abstract base class and cannot be used directly in a KML file. It provides * the id attribute, which allows unique identification of a KML element, and the targetId * attribute, which is used to reference objects that have already been loaded into * Google Earth. The id attribute must be assigned if the Update mechanism is to * be used. *

* * Syntax: *
<!-- abstract element; do not create -->
     * <!-- Object id="ID" targetId="NCName" -->
     * <!-- /Object> -->
* * * */ @XmlElement(name = "KmlObjectExtensionGroup") protected List kmlObjectExtension; @XmlAttribute(name = "hint") protected String hint; private transient JAXBContext jc = null; private transient Marshaller m = null; private transient int missingNameCounter = (1); private final static String SCHEMA_LOCATION = "src/main/resources/schema/ogckml/ogckml22.xsd"; public Kml() { super(); } /** * * * @return * possible object is * {@link NetworkLinkControl} * */ public NetworkLinkControl getNetworkLinkControl() { return networkLinkControl; } /** * * * @param value * allowed object is * {@link NetworkLinkControl} * */ public void setNetworkLinkControl(NetworkLinkControl value) { this.networkLinkControl = value; } /** * * * @return * possible object is * {@code <}{@link Container}{@code >} * {@code <}{@link GroundOverlay}{@code >} * {@code <}{@link NetworkLink}{@code >} * {@code <}{@link Folder}{@code >} * {@code <}{@link PhotoOverlay}{@code >} * {@code <}{@link Document}{@code >} * {@code <}{@link Tour}{@code >} * {@code <}{@link ScreenOverlay}{@code >} * {@code <}{@link Feature}{@code >} * {@code <}{@link Placemark}{@code >} * {@code <}{@link Overlay}{@code >} * */ public Feature getFeature() { return feature; } /** * * * @param value * allowed object is * {@code <}{@link Container}{@code >} * {@code <}{@link GroundOverlay}{@code >} * {@code <}{@link NetworkLink}{@code >} * {@code <}{@link Folder}{@code >} * {@code <}{@link PhotoOverlay}{@code >} * {@code <}{@link Document}{@code >} * {@code <}{@link Tour}{@code >} * {@code <}{@link ScreenOverlay}{@code >} * {@code <}{@link Feature}{@code >} * {@code <}{@link Placemark}{@code >} * {@code <}{@link Overlay}{@code >} * */ public void setFeature(Feature value) { this.feature = ((Feature ) value); } /** * * */ public List getKmlSimpleExtension() { if (kmlSimpleExtension == null) { kmlSimpleExtension = new ArrayList(); } return this.kmlSimpleExtension; } /** * * */ public List getKmlObjectExtension() { if (kmlObjectExtension == null) { kmlObjectExtension = new ArrayList(); } return this.kmlObjectExtension; } /** * * * @return * possible object is * {@link String} * */ public String getHint() { return hint; } /** * * * @param value * allowed object is * {@link String} * */ public void setHint(String value) { this.hint = value; } @Override public int hashCode() { final int prime = 31; int result = 1; result = ((prime*result)+((networkLinkControl == null)? 0 :networkLinkControl.hashCode())); result = ((prime*result)+((feature == null)? 0 :feature.hashCode())); result = ((prime*result)+((kmlSimpleExtension == null)? 0 :kmlSimpleExtension.hashCode())); result = ((prime*result)+((kmlObjectExtension == null)? 0 :kmlObjectExtension.hashCode())); result = ((prime*result)+((hint == null)? 0 :hint.hashCode())); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if ((obj instanceof Kml) == false) { return false; } Kml other = ((Kml) obj); if (networkLinkControl == null) { if (other.networkLinkControl!= null) { return false; } } else { if (networkLinkControl.equals(other.networkLinkControl) == false) { return false; } } if (feature == null) { if (other.feature!= null) { return false; } } else { if (feature.equals(other.feature) == false) { return false; } } if (kmlSimpleExtension == null) { if (other.kmlSimpleExtension!= null) { return false; } } else { if (kmlSimpleExtension.equals(other.kmlSimpleExtension) == false) { return false; } } if (kmlObjectExtension == null) { if (other.kmlObjectExtension!= null) { return false; } } else { if (kmlObjectExtension.equals(other.kmlObjectExtension) == false) { return false; } } if (hint == null) { if (other.hint!= null) { return false; } } else { if (hint.equals(other.hint) == false) { return false; } } return true; } /** * Creates a new instance of {@link NetworkLinkControl} and set it to networkLinkControl. * * This method is a short version for: * {@code * NetworkLinkControl networkLinkControl = new NetworkLinkControl(); * this.setNetworkLinkControl(networkLinkControl); } * * */ public NetworkLinkControl createAndSetNetworkLinkControl() { NetworkLinkControl newValue = new NetworkLinkControl(); this.setNetworkLinkControl(newValue); return newValue; } /** * Creates a new instance of {@link Tour} and set it to feature. * * This method is a short version for: * {@code * Tour tour = new Tour(); * this.setFeature(tour); } * * */ public Tour createAndSetTour() { Tour newValue = new Tour(); this.setFeature(newValue); return newValue; } /** * Creates a new instance of {@link ScreenOverlay} and set it to feature. * * This method is a short version for: * {@code * ScreenOverlay screenOverlay = new ScreenOverlay(); * this.setFeature(screenOverlay); } * * */ public ScreenOverlay createAndSetScreenOverlay() { ScreenOverlay newValue = new ScreenOverlay(); this.setFeature(newValue); return newValue; } /** * Creates a new instance of {@link PhotoOverlay} and set it to feature. * * This method is a short version for: * {@code * PhotoOverlay photoOverlay = new PhotoOverlay(); * this.setFeature(photoOverlay); } * * */ public PhotoOverlay createAndSetPhotoOverlay() { PhotoOverlay newValue = new PhotoOverlay(); this.setFeature(newValue); return newValue; } /** * Creates a new instance of {@link GroundOverlay} and set it to feature. * * This method is a short version for: * {@code * GroundOverlay groundOverlay = new GroundOverlay(); * this.setFeature(groundOverlay); } * * */ public GroundOverlay createAndSetGroundOverlay() { GroundOverlay newValue = new GroundOverlay(); this.setFeature(newValue); return newValue; } /** * Creates a new instance of {@link NetworkLink} and set it to feature. * * This method is a short version for: * {@code * NetworkLink networkLink = new NetworkLink(); * this.setFeature(networkLink); } * * */ public NetworkLink createAndSetNetworkLink() { NetworkLink newValue = new NetworkLink(); this.setFeature(newValue); return newValue; } /** * Creates a new instance of {@link Folder} and set it to feature. * * This method is a short version for: * {@code * Folder folder = new Folder(); * this.setFeature(folder); } * * */ public Folder createAndSetFolder() { Folder newValue = new Folder(); this.setFeature(newValue); return newValue; } /** * Creates a new instance of {@link Document} and set it to feature. * * This method is a short version for: * {@code * Document document = new Document(); * this.setFeature(document); } * * */ public Document createAndSetDocument() { Document newValue = new Document(); this.setFeature(newValue); return newValue; } /** * Creates a new instance of {@link Placemark} and set it to feature. * * This method is a short version for: * {@code * Placemark placemark = new Placemark(); * this.setFeature(placemark); } * * */ public Placemark createAndSetPlacemark() { Placemark newValue = new Placemark(); this.setFeature(newValue); return newValue; } /** * * * @param kmlSimpleExtension * Objects of the following type are allowed in the list: {@link Object} */ public void setKmlSimpleExtension(final List kmlSimpleExtension) { this.kmlSimpleExtension = kmlSimpleExtension; } /** * add a value to the kmlSimpleExtension property collection * * @param kmlSimpleExtension * Objects of the following type are allowed in the list: {@link Object} * @return * true (as general contract of Collection.add). */ public Kml addToKmlSimpleExtension(final Object kmlSimpleExtension) { this.getKmlSimpleExtension().add(kmlSimpleExtension); return this; } /** * * * @param kmlObjectExtension * Objects of the following type are allowed in the list: {@link AbstractObject} */ public void setKmlObjectExtension(final List kmlObjectExtension) { this.kmlObjectExtension = kmlObjectExtension; } /** * add a value to the kmlObjectExtension property collection * * @param kmlObjectExtension * Objects of the following type are allowed in the list: {@link AbstractObject} * @return * true (as general contract of Collection.add). */ public Kml addToKmlObjectExtension(final AbstractObject kmlObjectExtension) { this.getKmlObjectExtension().add(kmlObjectExtension); return this; } /** * fluent setter * * * @param networkLinkControl * required parameter */ public Kml withNetworkLinkControl(final NetworkLinkControl networkLinkControl) { this.setNetworkLinkControl(networkLinkControl); return this; } /** * fluent setter * * * @param feature * required parameter */ public Kml withFeature(final Feature feature) { this.setFeature(feature); return this; } /** * fluent setter * * * @param kmlSimpleExtension * required parameter */ public Kml withKmlSimpleExtension(final List kmlSimpleExtension) { this.setKmlSimpleExtension(kmlSimpleExtension); return this; } /** * fluent setter * * * @param kmlObjectExtension * required parameter */ public Kml withKmlObjectExtension(final List kmlObjectExtension) { this.setKmlObjectExtension(kmlObjectExtension); return this; } /** * fluent setter * * * @param hint * required parameter */ public Kml withHint(final String hint) { this.setHint(hint); return this; } /** * * */ private JAXBContext getJaxbContext() throws JAXBException { if (jc == null) { jc = JAXBContext.newInstance((Kml.class)); } return jc; } private Marshaller createMarshaller() throws JAXBException { if (m == null) { m = this.getJaxbContext().createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); //m.setProperty("com.sun.xml.bind.namespacePrefixMapper", new Kml.NameSpaceBeautyfier()); } return m; } /** * Internal method * */ private void addKmzFile(Kml kmzFile, ZipOutputStream out, boolean mainfile) throws IOException { String fileName = null; if (((kmzFile.getFeature() == null)||(kmzFile.getFeature().getName() == null))||(kmzFile.getFeature().getName().length() == 0)) { fileName = (("noFeatureNameSet"+ missingNameCounter ++)+".kml"); } else { fileName = kmzFile.getFeature().getName(); if (!fileName.endsWith(".kml")) { fileName += ".kml"; } } if (mainfile) { fileName = "doc.kml"; } out.putNextEntry(new ZipEntry(URLEncoder.encode(fileName, "UTF-8"))); kmzFile.marshal(out); out.closeEntry(); } /** * Java to KML * The object graph is marshalled to an OutputStream object. * The object is not saved as a zipped .kmz file. * * */ public boolean marshal(final OutputStream outputstream) throws FileNotFoundException { try { m = this.createMarshaller(); m.marshal(this, outputstream); return true; } catch (JAXBException _x) { _x.printStackTrace(); return false; } } /** * Java to KML * The object graph is marshalled to a Writer object. * The object is not saved as a zipped .kmz file. * * */ public boolean marshal(final Writer writer) { try { m = this.createMarshaller(); m.marshal(this, writer); return true; } catch (JAXBException _x) { _x.printStackTrace(); return false; } } /** * Java to KML * The object graph is marshalled to a Contenthandler object. * Useful if marshaller cis needed to generate CDATA blocks. * @see ... * @see ... * The object is not saved as a zipped .kmz file. * * */ public boolean marshal(final ContentHandler contenthandler) { try { m = this.createMarshaller(); m.marshal(this, contenthandler); return true; } catch (JAXBException _x) { _x.printStackTrace(); return false; } } /** * Java to KML * The object graph is printed to the console. * (Nothing is saved, nor saved. Just printed.) * * */ public boolean marshal() { try { m = this.createMarshaller(); m.marshal(this, System.out); return true; } catch (JAXBException _x) { _x.printStackTrace(); return false; } } /** * Java to KML * The object graph is marshalled to a File object. * The object is not saved as a zipped .kmz file. * * */ public boolean marshal(final File filename) throws FileNotFoundException { OutputStream out = new FileOutputStream(filename); return this.marshal(out); } public boolean marshalAsKmz( @NotNull String name, Kml... additionalFiles) throws IOException { ZipOutputStream out = new ZipOutputStream(new FileOutputStream(name)); out.setComment("KMZ-file created with Java API for KML. Visit us: http://code.google.com/p/javaapiforkml/"); this.addKmzFile(this, out, true); for (Kml kml: additionalFiles) { this.addKmzFile(kml, out, false); } out.close(); missingNameCounter = 1; return false; } private static boolean validate(final Unmarshaller unmarshaller) { try { SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); File schemaFile = new File(SCHEMA_LOCATION); Schema schema = sf.newSchema(schemaFile); unmarshaller.setSchema(schema); return true; } catch (SAXException _x) { _x.printStackTrace(); } return false; } /** * KML to Java * KML given as a file object is transformed into a graph of Java objects. * The boolean value indicates, whether the File object should be validated * automatically during unmarshalling and be checked if the object graph meets * all constraints defined in OGC's KML schema specification. * */ public static Kml unmarshal(final File file, final boolean validate) { try { Unmarshaller unmarshaller = JAXBContext.newInstance((Kml.class)).createUnmarshaller(); if (validate == true) { Kml.validate(unmarshaller); } InputSource input = new InputSource(new FileReader(file)); SAXSource saxSource = new SAXSource(new NamespaceFilterXMLReader(validate), input); Kml jaxbRootElement = ((Kml) unmarshaller.unmarshal(saxSource)); return jaxbRootElement; } catch (SAXException _x) { _x.printStackTrace(); } catch (ParserConfigurationException _x) { _x.printStackTrace(); } catch (JAXBException _x) { _x.printStackTrace(); } catch (FileNotFoundException _x) { _x.printStackTrace(); } return null; } /** * KML to Java * KML given as a file object is transformed into a graph of Java objects. * Similar to the method: * unmarshal(final File, final boolean) * with the exception that the File object is not validated (boolean is false). * */ public static Kml unmarshal(final File file) { return Kml.unmarshal(file, false); } /** * KML to Java * Similar to the other unmarshal methods * * with the exception that it transforms a String into a graph of Java objects. * * */ public static Kml unmarshal(final String content) { try { Unmarshaller unmarshaller = JAXBContext.newInstance((Kml.class)).createUnmarshaller(); InputSource input = new InputSource(new StringReader(content)); SAXSource saxSource = new SAXSource(new NamespaceFilterXMLReader(false), input); Kml jaxbRootElement = ((Kml) unmarshaller.unmarshal(saxSource)); return jaxbRootElement; } catch (SAXException _x) { _x.printStackTrace(); } catch (ParserConfigurationException _x) { _x.printStackTrace(); } catch (JAXBException _x) { _x.printStackTrace(); } return null; } /** * KML to Java * Similar to the other unmarshal methods * * with the exception that it transforms a InputStream into a graph of Java objects. * * */ public static Kml unmarshal(final InputStream content) { try { Unmarshaller unmarshaller = JAXBContext.newInstance((Kml.class)).createUnmarshaller(); InputSource input = new InputSource(content); SAXSource saxSource = new SAXSource(new NamespaceFilterXMLReader(false), input); Kml jaxbRootElement = ((Kml) unmarshaller.unmarshal(saxSource)); return jaxbRootElement; } catch (SAXException _x) { _x.printStackTrace(); } catch (ParserConfigurationException _x) { _x.printStackTrace(); } catch (JAXBException _x) { _x.printStackTrace(); } return null; } /** * KMZ to Java * Similar to the other unmarshal methods * * with the exception that it transforms a KMZ-file into a graph of Java objects. * * */ public static Kml[] unmarshalFromKmz( @NotNull File file) throws IOException { Kml[] EMPTY_KML_ARRAY = (new Kml[0]); if (!file.getName().endsWith(".kmz")) { return EMPTY_KML_ARRAY; } ZipFile zip = new ZipFile(file); Enumeration entries = zip.entries(); if (!file.exists()) { return EMPTY_KML_ARRAY; } ArrayList kmlfiles = new ArrayList(); while (entries.hasMoreElements()) { ZipEntry entry = ((ZipEntry) entries.nextElement()); if (entry.getName().contains("__MACOSX")||entry.getName().contains(".DS_STORE")) { continue; } String entryName = URLDecoder.decode(entry.getName(), "UTF-8"); if (!entryName.endsWith(".kml")) { continue; } InputStream in = zip.getInputStream(entry); Kml unmarshal = Kml.unmarshal(in); kmlfiles.add(unmarshal); } zip.close(); return kmlfiles.toArray(EMPTY_KML_ARRAY); } @Override public Kml clone() { Kml copy; try { copy = ((Kml) super.clone()); } catch (CloneNotSupportedException _x) { throw new InternalError((_x.toString())); } copy.networkLinkControl = ((networkLinkControl == null)?null:((NetworkLinkControl) networkLinkControl.clone())); copy.feature = ((feature == null)?null:((Feature ) feature.clone())); copy.kmlSimpleExtension = new ArrayList((getKmlSimpleExtension().size())); for (Object iter: kmlSimpleExtension) { copy.kmlSimpleExtension.add(iter); } copy.kmlObjectExtension = new ArrayList((getKmlObjectExtension().size())); for (AbstractObject iter: kmlObjectExtension) { copy.kmlObjectExtension.add(iter.clone()); } return copy; } // private final static class NameSpaceBeautyfier // extends NamespacePrefixMapper // { // // // /** // * Internal method! // *

Customizing Namespace Prefixes During Marshalling to a more readable format.

// *

The default output is like:

// *
{@code<kml ... xmlns:ns2="http://www.w3.org/2005/Atom" xmlns:ns3="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0" xmlns:ns4="http://www.google.com/kml/ext/2.2">}
// *

is changed to:

// *
{@code <kml ... xmlns:atom="http://www.w3.org/2005/Atom" xmlns:xal="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0" xmlns:gx="http://www.google.com/kml/ext/2.2">}

What it does:

// *

namespaceUri: http://www.w3.org/2005/Atom prefix: atom

namespaceUri: urn:oasis:names:tc:ciq:xsdschema:xAL:2.0 prefix: xal

namespaceUri: http://www.google.com/kml/ext/2.2 prefix: gx

namespaceUri: anything else prefix: null

// * // */ // @Override // public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) { // if (namespaceUri.matches("http://www.w3.org/\\d{4}/Atom")) { // return "atom"; // } // if (namespaceUri.matches("urn:oasis:names:tc:ciq:xsdschema:xAL:.*?")) { // return "xal"; // } // if (namespaceUri.matches("http://www.google.com/kml/ext/.*?")) { // return "gx"; // } // return null; // } // // } }