/* * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI * for visualizing and manipulating spatial features with geometry and attributes. * * Copyright (C) 2003 Vivid Solutions * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * For more information, contact: * * Vivid Solutions * Suite #1A * 2328 Government Street * Victoria BC V8T 5G5 * Canada * * (250)385-6040 * www.vividsolutions.com */ package com.vividsolutions.jump.io; import java.io.BufferedReader; import java.util.ArrayList; /** * This class provides a parser for reading GMLOuputTemplates. This does NOT contain an evaluator for <br> * taking the parsed GMLOutputTemplate and a featureCollection and producing properly <bR> * formatted output GML. Thats the {@link GMLWriter} class.<br> *<br> *<br> * Most people will just use the load() function, but there is support for directly <br> *constructing/modifying one. Your best bet for hand creating one is to make a String that <br> *contains a GMLOutputTemplate then make a java.io.StringReader and passing it to the load()<br> *method. <br> *The valuators (things that look like "<%") are:<br> * <%=GEOMETRY> - replace this with a GML represention of the geometry<br> * <%=COLUMN <column name>> - replace this with the corresponding JCS column value <br> * <%FEATURE> - this marks the start of a feature in the OutputTemplate <Br> * <%ENDFEATURE> - This marks the end of a feature in the OutputTempalte <br> *<br> *<br> *Here's an example of how a simple GMLOutputTemplate is parsed by this class: *for input like: *<br> *<?xml version='1.0' encoding='UTF-8'?> <br> *<dataset...> <br> *<schemaFeatures> <br> *<gml:featureMember> <br> *<% FEATURE %> <br> *<Feature> <br> *<featureType> <%=COLUMN featureType %> </featureType> <br> *<property fme:name="ID"> <%=COLUMN ID %> </property> <br> *<property fme:name="SITE"> <%=COLUMN SITE %> </property> <br> *<property fme:name="gml2_coordsys"></property> <br> *<gml:pointProperty> <br> * <%=GEOMETRY %> <br> *</gml:pointProperty> <br> *</Feature> <br> *<% ENDFEATURE %> <br> *</gml:featureMember> <br> *</dataFeatures> <br> *</dataset> <br> * <br> * <br> * headeText = <br> * <br> *<?xml version='1.0' encoding='UTF-8'?> <br> *<dataset...> <br> *<schemaFeatures> <br> *<gml:featureMember> <br> * <br> * footerText = <br> *</gml:featureMember> <br> *</dataFeatures> <br> *</dataset> <br> * <br> * <br> *featureText[0] = <br> *<Feature> <br> *<featureType> <br> * <br> * codingText[0] = "=COLUMN featureTtype" <br> * <br> *featureText[1] = <br> *</property> <br> *<property fme:name="SITE"> <br> * <br> *codingText[1] = "=COLUMN ID" <br> **/ public class GMLOutputTemplate { String headerText; String footerText; String AllFeatureText; ArrayList featureText = new ArrayList(); ArrayList codingText = new ArrayList(); String featureTextfooter; int lineNumber = 0; String streamName; /** constructor**/ public GMLOutputTemplate() { } /** sets the HeaderText for the Outputtemplate */ public void setHeaderText(String text) { headerText = text; } /** sets the FooterText for the Outputtemplate */ public void setFooterText(String text) { footerText = text; } /** sets the Footer text for the bottom of the feature*/ public void setFeatureFooter(String text) { featureTextfooter = text; } /** *for input like : <br> * <feature> <PROPERTY type=name> <%=NAME></property> <PROPERTY type=address> <%=ADDRESS> </property><br> *<br> * use addItem("<feature> <PROPERTY type=name>","=NAME")<br> * addItem("</property> <PROPERTY type=address>", "%=ADDRESS")<br> * **/ public void addItem(String header, String coding) { featureText.add(header); codingText.add(coding); } /** * Calls the main load() method with the stream name as "Unknown Stream" */ public void load(java.io.Reader r) throws Exception { load(r, "Unknown Stream"); } /** * Gets a line from the input Stream */ private String getLine(BufferedReader br) throws Exception { lineNumber++; return br.readLine(); } /** *Main function - parse a GMLOuputTemplate. *@param r actual reader to read from *@param readerName name of the stream (for error reporting) */ public void load(java.io.Reader r, String readerName) throws Exception { int index; int index2; String line; boolean keepgoing; String token; String textAccum; boolean justFoundTag = false; BufferedReader buffRead = new BufferedReader(r); streamName = readerName; // find the header headerText = ""; keepgoing = true; line = ""; index = 0; while (keepgoing && ((line = getLine(buffRead)) != null)) { if ((index = line.indexOf("<%")) != -1) { //found a "<%" tag, look for the "%>" tag index2 = line.indexOf("%>", index); if (index2 == -1) { throw new ParseException("While trying to find the GML output header, found a <%, but no %>", streamName, lineNumber, index); } token = line.substring(index + 2, index2); token = token.trim(); if (!(token.equalsIgnoreCase("FEATURE"))) { throw new ParseException("While trying to find the GML output header, found a <%..%> that isnt a <%FEATURE%>", streamName, lineNumber, index); } keepgoing = false; headerText = headerText + line.substring(0, index); line = line.substring(index2 + 2); } else { headerText = headerText + line + "\n"; } } if (line == null) { throw new ParseException("Unexpected EOF while looking for header", streamName, lineNumber, index); } //find the feature text AllFeatureText = ""; keepgoing = true; textAccum = ""; while (keepgoing) { if ((index = line.indexOf("<%")) != -1) { //found a "<%" tag, look for the "%>" tag index2 = line.indexOf("%>", index); if (index2 == -1) { throw new ParseException("While looking at the GML feature text, found a <%, but no %>", streamName, lineNumber, index); } token = line.substring(index + 2, index2).trim(); if (token.equalsIgnoreCase("ENDFEATURE")) { keepgoing = false; AllFeatureText = AllFeatureText + line.substring(0, index); featureTextfooter = textAccum + line.substring(0, index); line = line.substring(index2 + 2); } else { //handle a part of the feature spec\ if (!(validop(token))) { throw new ParseException("invalid token in <%..%> :" + token, streamName, lineNumber, index); } justFoundTag = true; String pre = textAccum + line.substring(0, index); textAccum = line.substring(index2 + 2); featureText.add(pre); codingText.add(token); } } if (keepgoing) { AllFeatureText = AllFeatureText + line + "\n"; if (!(justFoundTag)) { textAccum = textAccum + line + "\n"; } else { justFoundTag = false; //textAccum already has a portion of line in it. textAccum = textAccum + "\n"; } line = getLine(buffRead); if (line == null) { throw new ParseException("Unexpected EOF while looking for feature", streamName, lineNumber, index); } } } // grab the footer footerText = line; while ((line = getLine(buffRead)) != null) { footerText = footerText + line + "\n"; } //System.out.println(this.asString()); } /** * For debugging - return a human readable version of the parsed outputtemplate */ public String asString() { String result; int t; result = headerText + "\n--------------------------------------\n"; for (t = 0; t < featureText.size(); t++) { result = result + featureText.get(t) + "<%" + codingText.get(t) + "%>"; } result = result + featureTextfooter; result = result + "\n--------------------------------------\n"; result = result + footerText; return result; } /** * returns true if the intput string is a valid op (for error checking) *@param op test string that should contain an op */ private boolean validop(String op) { String op2; op2 = new String(op); op2 = op2.trim(); op2 = op2.toLowerCase(); if (!(op2.startsWith("=")) || (op2.length() < 2)) { return false; } op2 = op2.substring(1); op2 = op2.trim(); return (op2.startsWith("column") || op2.startsWith("geometry")); } }