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


package de.micromata.opengis.kml.v_2_2_0;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.Writer;
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;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.sax.SAXSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import com.sun.istack.NotNull;
import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
import de.micromata.opengis.kml.v_2_2_0.gx.Tour;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;


/**
 * 
 * 

* ... * *

*

* A basic element contains 0 or 1 Feature and 0 or 1 NetworkLinkControl: *

*

* The 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 { /** * *

* Controls the behavior of files fetched by a . *

* * 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: * * * * * */ @XmlElement(name = "NetworkLinkControl") protected NetworkLinkControl networkLinkControl; /** * *

* 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: * @see: * * Extended By: * @see: * @see: * @see: * @see: * @see: * * * */ @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; /** * *

* 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 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(); } /** * @see networkLinkControl * * @return * possible object is * {@link NetworkLinkControl} * */ public NetworkLinkControl getNetworkLinkControl() { return networkLinkControl; } /** * @see networkLinkControl * * @param value * allowed object is * {@link NetworkLinkControl} * */ public void setNetworkLinkControl(NetworkLinkControl value) { this.networkLinkControl = value; } /** * @see feature * * @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; } /** * @see 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); } /** * @see kmlSimpleExtension * */ public List getKmlSimpleExtension() { if (kmlSimpleExtension == null) { kmlSimpleExtension = new ArrayList(); } return this.kmlSimpleExtension; } /** * @see kmlObjectExtension * */ public List getKmlObjectExtension() { if (kmlObjectExtension == null) { kmlObjectExtension = new ArrayList(); } return this.kmlObjectExtension; } /** * @see hint * * @return * possible object is * {@link String} * */ public String getHint() { return hint; } /** * @see 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: * * 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: * * 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: * * 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: * * 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: * * 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: * * 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: * * 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: * * 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: * * Placemark placemark = new Placemark(); * this.setFeature(placemark); * * */ public Placemark createAndSetPlacemark() { Placemark newValue = new Placemark(); this.setFeature(newValue); return newValue; } /** * @see kmlSimpleExtension * * @param kmlSimpleExtension */ 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; } /** * @see kmlObjectExtension * * @param kmlObjectExtension */ 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 * @see #setNetworkLinkControl(NetworkLinkControl) * * @param networkLinkControl * required parameter */ public Kml withNetworkLinkControl(final NetworkLinkControl networkLinkControl) { this.setNetworkLinkControl(networkLinkControl); return this; } /** * fluent setter * @see #setFeature(Feature) * * @param feature * required parameter */ public Kml withFeature(final Feature feature) { this.setFeature(feature); return this; } /** * fluent setter * @see #setKmlSimpleExtension(List) * * @param kmlSimpleExtension * required parameter */ public Kml withKmlSimpleExtension(final List kmlSimpleExtension) { this.setKmlSimpleExtension(kmlSimpleExtension); return this; } /** * fluent setter * @see #setKmlObjectExtension(List) * * @param kmlObjectExtension * required parameter */ public Kml withKmlObjectExtension(final List kmlObjectExtension) { this.setKmlObjectExtension(kmlObjectExtension); return this; } /** * fluent setter * @see #setHint(String) * * @param hint * required parameter */ public Kml withHint(final String hint) { this.setHint(hint); return this; } /** * @see jaxbContext * */ 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. * @see marshalKmz(String, Kml...) * */ 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. * @see marshalKmz(String, Kml...) * */ 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. * {@link https://jaxb.dev.java.net/faq/} * {@link http://code.google.com/p/javaapiforkml/issues/detail?id=7} * The object is not saved as a zipped .kmz file. * @see marshalKmz(String, Kml...) * */ 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. * @see marshalKmz(String, Kml...) * */ 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; } } }