Package org.geotools.filter

Source Code of org.geotools.filter.ExpressionDOMParser

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
*   
*    This library is free software; you can redistribute it and/or
*    modify it under the terms of the GNU Lesser General Public
*    License as published by the Free Software Foundation;
*    version 2.1 of the License.
*
*    This library 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
*    Lesser General Public License for more details.
*
*    Created on 03 July 2002, 10:21
*/
package org.geotools.filter;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Logger;

import org.geotools.factory.CommonFactoryFinder;
import org.geotools.referencing.CRS;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.PropertyName;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.helpers.NamespaceSupport;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.TopologyException;

/**
* parsez short sections of gml for use in expressions and filters Hopefully we
* can get away without a full parser here.
*
* @author iant
* @author Niels Charlier
*
*
* @source $URL$
*/
public final class ExpressionDOMParser {
    /** The logger for the filter module. */
    private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.filter");

    /** Factory for creating filters. */
    private FilterFactory2 ff;
   
    /** Factory for creating geometry objects */
    private static GeometryFactory gfac = new GeometryFactory();

    /** int representation of a box */
    private static final int GML_BOX = 1;

    /** int representation of a polygon */
    private static final int GML_POLYGON = 2;

    /** int representation of a linestring */
    private static final int GML_LINESTRING = 3;

    /** int representation of a point */
    private static final int GML_POINT = 4;

    /** number of coordinates in a box */
    private static final int NUM_BOX_COORDS = 5;

    /**
     * Creates a new instance of ExpressionXmlParser
     */
    private ExpressionDOMParser() {
      this( CommonFactoryFinder.getFilterFactory2( null ) );     
        LOGGER.finer("made new logic factory");
    }
    /** Constructor injection */
    public ExpressionDOMParser( FilterFactory2 factory ){
      ff = factory != null ? factory : CommonFactoryFinder.getFilterFactory2( null );
    }
    /** Setter injection */
    public void setFilterFactory( FilterFactory2 factory ){
      ff = factory;
    }
   
 
    private static NamespaceSupport getNameSpaces(Node node)
    {
        NamespaceSupport namespaces = new NamespaceSupport();
        while (node != null)
        {
            NamedNodeMap atts = node.getAttributes();
           
            if (atts != null) {
                for (int i=0; i<atts.getLength(); i++){
                    Node att = atts.item(i);
                   
                    if (att.getNamespaceURI() != null
                            && att.getNamespaceURI().equals("http://www.w3.org/2000/xmlns/")
                            && namespaces.getURI(att.getLocalName()) == null){
                        namespaces.declarePrefix(att.getLocalName(), att.getNodeValue());
                    }
                }
            }
           
            node = node.getParentNode();
        }
       
        return namespaces;
    }
   
    /**
     *
     * @deprecated Please use ExpressionDOMParser.expression
     * @param root
     */
    public static Expression parseExpression( Node root ){
      ExpressionDOMParser parser = new ExpressionDOMParser();
      return parser.expression( root );
    }
    /**
     * parses an expression for a filter.
     *
     * @param root the root node to parse, should be an filter expression.
     *
     * @return the geotools representation of the expression held in the node.
     */
    public Expression expression(Node root) {
        LOGGER.finer("parsingExpression " + root.getLocalName());

        //NodeList children = root.getChildNodes();
        //LOGGER.finest("children "+children);
        if ((root == null) || (root.getNodeType() != Node.ELEMENT_NODE)) {
            LOGGER.finer("bad node input ");

            return null;
        }

        LOGGER.finer("processing root " + root.getLocalName());

        Node child = root;

        String childName = (child.getLocalName() != null)
            ? child.getLocalName() : child.getNodeName();
       
        if (childName.indexOf(':') != -1)
        {
          //the DOM parser wasnt properly set to handle namespaces...
          childName = childName.substring(childName.indexOf(':')+1);
        }

        if (childName.equalsIgnoreCase("Literal")) {
            LOGGER.finer("processing literal " + child);

            NodeList kidList = child.getChildNodes();
            LOGGER.finest("literal elements (" + kidList.getLength() + ") "
                + kidList.toString());

            for (int i = 0; i < kidList.getLength(); i++) {
                Node kid = kidList.item(i);
                LOGGER.finest("kid " + i + " " + kid);

                if (kid == null) {
                    LOGGER.finest("Skipping ");

                    continue;
                }

                if (kid.getNodeValue() == null) {
                    /* it might be a gml string so we need to convert it into
                     * a geometry this is a bit tricky since our standard
                     * gml parser is SAX based and we're a DOM here.
                     */
                    LOGGER.finer("node " + kid.getNodeValue() + " namespace "
                        + kid.getNamespaceURI());
                    LOGGER.fine("a literal gml string?");

                    try {
                        Geometry geom = parseGML(kid);

                        if (geom != null) {
                            LOGGER.finer("built a " + geom.getGeometryType()
                                + " from gml");
                            LOGGER.finer("\tpoints: " + geom.getNumPoints());
                        } else {
                            LOGGER.finer(
                                "got a null geometry back from gml parser");
                        }

                        return ff.literal(geom);
                    } catch (IllegalFilterException ife) {
                        LOGGER.warning("Problem building GML/JTS object: "
                            + ife);
                    }

                    return null;
                }

                // CDATA shouldn't be interpretted
                if (kid.getNodeType() != Node.CDATA_SECTION_NODE && kid.getNodeValue().trim().length() == 0) {
                    LOGGER.finest("empty text element");

                    continue;
                }

                // debuging only

                /*switch(kid.getNodeType()){
                   case Node.ELEMENT_NODE:
                       LOGGER.finer("element :"+kid);
                       break;
                   case Node.TEXT_NODE:
                       LOGGER.finer("text :"+kid);
                       break;
                   case Node.ATTRIBUTE_NODE:
                       LOGGER.finer("Attribute :"+kid);
                       break;
                   case Node.CDATA_SECTION_NODE:
                       LOGGER.finer("Cdata :"+kid);
                       break;
                   case Node.COMMENT_NODE:
                       LOGGER.finer("comment :"+kid);
                       break;
                   } */
                String nodeValue = kid.getNodeValue();
                LOGGER.finer("processing " + nodeValue);

                try {
                    //always store internal values as strings.  We might lose info otherwise.
                    return ff.literal(nodeValue);
                } catch (IllegalFilterException ife) {
                    LOGGER.finer("Unable to build expression " + ife);
                    return null;
                }
            }
            // creates an empty literal expression if there is nothing inside the literal
            return ff.literal("");
        }

        if (childName.equalsIgnoreCase("add")) {
            try {
                LOGGER.fine("processing an Add");

                //Node left = null;
                //Node right = null;
                Node value = child.getFirstChild();

                while (value.getNodeType() != Node.ELEMENT_NODE) {
                    value = value.getNextSibling();
                }

                LOGGER.finer("add left value -> " + value + "<-");
                Expression left = parseExpression(value);
                value = value.getNextSibling();

                while (value.getNodeType() != Node.ELEMENT_NODE) {
                    value = value.getNextSibling();
                }

                LOGGER.finer("add right value -> " + value + "<-");
                Expression right = parseExpression(value);

                return ff.add( left, right );
            } catch (IllegalFilterException ife) {
                LOGGER.warning("Unable to build expression " + ife);
                return null;
            }
        }

        if (childName.equalsIgnoreCase("sub")) {
            try {
                //NodeList kids = child.getChildNodes();
                Node value = child.getFirstChild();

                while (value.getNodeType() != Node.ELEMENT_NODE) {
                    value = value.getNextSibling();
                }
                LOGGER.finer("add left value -> " + value + "<-");
                Expression left = parseExpression(value);
                value = value.getNextSibling();

                while (value.getNodeType() != Node.ELEMENT_NODE) {
                    value = value.getNextSibling();
                }

                LOGGER.finer("add right value -> " + value + "<-");
                Expression right = parseExpression(value);

                return ff.subtract( left, right );
            } catch (IllegalFilterException ife) {
                LOGGER.warning("Unable to build expression " + ife);

                return null;
            }
        }

        if (childName.equalsIgnoreCase("mul")) {
            try {
                //NodeList kids = child.getChildNodes();
                Node value = child.getFirstChild();

                while (value.getNodeType() != Node.ELEMENT_NODE) {
                    value = value.getNextSibling();
                }

                LOGGER.finer("add left value -> " + value + "<-");
                Expression left = parseExpression(value);
                value = value.getNextSibling();

                while (value.getNodeType() != Node.ELEMENT_NODE) {
                    value = value.getNextSibling();
                }

                LOGGER.finer("add right value -> " + value + "<-");
                Expression right = parseExpression(value);

                return ff.multiply( left, right );
            } catch (IllegalFilterException ife) {
                LOGGER.warning("Unable to build expression " + ife);

                return null;
            }
        }

        if (childName.equalsIgnoreCase("div")) {
            try {
                Node value = child.getFirstChild();

                while (value.getNodeType() != Node.ELEMENT_NODE) {
                    value = value.getNextSibling();
                }

                LOGGER.finer("add left value -> " + value + "<-");
                Expression left = parseExpression(value);
                value = value.getNextSibling();

                while (value.getNodeType() != Node.ELEMENT_NODE) {
                    value = value.getNextSibling();
                }

                LOGGER.finer("add right value -> " + value + "<-");
                Expression right = parseExpression(value);

                return ff.divide( left, right );
            } catch (IllegalFilterException ife) {
                LOGGER.warning("Unable to build expression " + ife);

                return null;
            }
        }

        if (childName.equalsIgnoreCase("PropertyName")) {
            try {
              //JD: trim whitespace here
              String value = child.getFirstChild().getNodeValue();
              value = value != null ? value.trim() : value;
                PropertyName attribute = ff.property( value, getNameSpaces(root) );

                //                attribute.setAttributePath(child.getFirstChild().getNodeValue());
                return attribute;
            } catch (IllegalFilterException ife) {
                LOGGER.warning("Unable to build expression: " + ife);

                return null;
            }
        }

        if (childName.equalsIgnoreCase("Function")) {
            Element param = (Element) child;

            NamedNodeMap map = param.getAttributes();
            String funcName = null;

            for (int k = 0; k < map.getLength(); k++) {
                String res = map.item(k).getNodeValue();
                String name = map.item(k).getLocalName();

                if (name == null) {
                    name = map.item(k).getNodeName();
                }
                if (name.indexOf(':') != -1)
                {
                  //the DOM parser was not properly set to handle namespaces...
                  name = name.substring(name.indexOf(':')+1);
                }

                LOGGER.fine("attribute " + name + " with value of " + res);

                if (name.equalsIgnoreCase("name")) {
                    funcName = res;
                }
            }

            if (funcName == null) {
                LOGGER.severe("failed to find a function name in " + child);
                return null;
            }

            ArrayList<Expression> args = new ArrayList<Expression>();
            Node value = child.getFirstChild();

            ARGS: while( value != null ){
                while (value.getNodeType() != Node.ELEMENT_NODE) {
                    value = value.getNextSibling();
                    if( value == null )
                        break ARGS;
                }
                args.add( parseExpression(value) );
                value = value.getNextSibling();
            }
            Expression[] array = args.toArray( new Expression[0]);
            return ff.function( funcName, array );
        }

        if (child.getNodeType() == Node.TEXT_NODE) {
            LOGGER.finer("processing a text node " + root.getNodeValue());

            String nodeValue = root.getNodeValue();
            LOGGER.finer("Text name " + nodeValue);

            // see if it's an int
            try {
                try {
                    Integer intLiteral = new Integer(nodeValue);

                    return ff.literal(intLiteral);
                } catch (NumberFormatException e) {
                    /* really empty */
                }

                try {
                    Double doubleLit = new Double(nodeValue);

                    return ff.literal(doubleLit);
                } catch (NumberFormatException e) {
                    /* really empty */
                }

                return ff.literal(nodeValue);
            } catch (IllegalFilterException ife) {
                LOGGER.finer("Unable to build expression " + ife);
            }
        }

        return null;
    }

    /**
     * @deprecated Please use ExpressionDOMParser.gml
     * @param root
     * @return the java representation of the geometry contained in root.
     */
    public static Geometry parseGML(Node root) {
      ExpressionDOMParser parser = new ExpressionDOMParser();
      return parser.gml( root );
    }
   
   
    public Geometry gml(Node root) {
        // look for the SRS name, if available
        Node srsNameNode = root.getAttributes().getNamedItem("srsName");
        CoordinateReferenceSystem crs = null;
        if(srsNameNode != null) {
            String srs = srsNameNode.getTextContent();
            try {
                crs = CRS.decode(srs);
            } catch(Exception e) {
                LOGGER.warning("Failed to parse the specified SRS " + srs);
            }
        }
       
        // parse the geometry
        Geometry g = _gml(root);
       
        // force the crs if necessary
        if(crs != null) {
            g.setUserData(crs);
        }
       
        return g;
    }
   
    /**
     * Parses the gml of this node to jts.
     *
     * @param root the parent node of the gml to parse.
     * @return the java representation of the geometry contained in root.
     */
    private Geometry _gml(Node root) {
      LOGGER.finer("processing gml " + root);

        List coordList;
        int type = 0;
        Node child = root;

        //Jesus I hate DOM.  I have no idea why this was checking for localname
        //and then nodename - lead to non-deterministic behavior, that for
        //some reason only failed if the filter parser was used within the
        //SLDparser.  I really would like that class redone, so we don't have
        //to use this crappy DOM GML parser.
        String childName = child.getNodeName();
        if(childName == null)
        {
            childName = child.getLocalName();
        }
     if(!childName.startsWith("gml:"))
     {
                childName = "gml:" + childName;
        }
    
        if (childName.equalsIgnoreCase("gml:box")) {
            type = GML_BOX;
            coordList = parseCoords(child);
           
            com.vividsolutions.jts.geom.Envelope env = new com.vividsolutions.jts.geom.Envelope();

            for (int i = 0; i < coordList.size(); i++) {
                env.expandToInclude((Coordinate) coordList.get(i));
            }           
            Coordinate[] coords = new Coordinate[NUM_BOX_COORDS];
            coords[0] = new Coordinate(env.getMinX(), env.getMinY());
            coords[1] = new Coordinate(env.getMinX(), env.getMaxY());
            coords[2] = new Coordinate(env.getMaxX(), env.getMaxY());
            coords[3] = new Coordinate(env.getMaxX(), env.getMinY());
            coords[4] = new Coordinate(env.getMinX(), env.getMinY());

            //return new ReferencedEnvelope( env, null );
            com.vividsolutions.jts.geom.LinearRing ring = null;

            try {
                ring = gfac.createLinearRing(coords);
            } catch (com.vividsolutions.jts.geom.TopologyException tope) {
                LOGGER.fine("Topology Exception in GMLBox" + tope);

                return null;
            }
            return gfac.createPolygon(ring, null);
        }

        //check for geometry properties
        if (childName.equalsIgnoreCase("gml:polygonmember") ||
            childName.equalsIgnoreCase( "gml:pointmember") ||
            childName.equalsIgnoreCase( "gml:linestringmember") ||
            childName.equalsIgnoreCase( "gml:linearringmember" ) ) {
         
          for ( int i = 0; i < child.getChildNodes().getLength(); i++ ) {
            Node newChild = child.getChildNodes().item( i );
            if ( newChild.getNodeType() == Node.ELEMENT_NODE ) {
              childName = newChild.getNodeName();
              if ( !childName.startsWith("gml:" ) ) {
                childName = "gml:" + childName;
              }
              root = newChild;
              child = newChild;
              break;
            }
          }
        }
       
        if (childName.equalsIgnoreCase("gml:polygon")) {
            LOGGER.finer("polygon");
            type = GML_POLYGON;

            LinearRing outer = null;
            List inner = new ArrayList();
            NodeList kids = root.getChildNodes();

            for (int i = 0; i < kids.getLength(); i++) {
                Node kid = kids.item(i);
                LOGGER.finer("doing " + kid);

                String kidName = kid.getNodeName();
                if(kidName == null)
                {
                    kidName = child.getLocalName();
                }
                if(!kidName.startsWith("gml:"))
                {
                  kidName = "gml:" + kidName;
                }                      
        
   
                if (kidName.equalsIgnoreCase("gml:outerBoundaryIs")) {
                    outer = (LinearRing) parseGML(kid);
           }
         
                if (kidName.equalsIgnoreCase("gml:innerBoundaryIs")) {
                    inner.add((LinearRing) parseGML(kid));
                }
            }

            if (inner.size() > 0) {
                return gfac.createPolygon(outer,
                    (LinearRing[]) inner.toArray(new LinearRing[0]));
            } else {
                return gfac.createPolygon(outer, null);
            }
        }

        if (childName.equalsIgnoreCase("gml:outerBoundaryIs")
                || childName.equalsIgnoreCase("gml:innerBoundaryIs")) {
            LOGGER.finer("Boundary layer");

            NodeList kids = ((Element) child).getElementsByTagName(
                    "gml:LinearRing");
            if (kids.getLength() ==0)
              kids = ((Element) child).getElementsByTagName("LinearRing");
            return parseGML(kids.item(0));
        }

        if (childName.equalsIgnoreCase("gml:linearRing")) {
            LOGGER.finer("LinearRing");
            coordList = parseCoords(child);

            com.vividsolutions.jts.geom.LinearRing ring = null;

            try {
                ring = gfac.createLinearRing((Coordinate[]) coordList.toArray(
                            new Coordinate[] {  }));
            } catch (TopologyException te) {
                LOGGER.finer("Topology Exception build linear ring: " + te);

                return null;
            }

            return ring;
        }
       
        if (childName.equalsIgnoreCase("gml:linestring")) {
            LOGGER.finer("linestring");
            type = GML_LINESTRING;
            coordList = parseCoords(child);

            com.vividsolutions.jts.geom.LineString line = null;
            line = gfac.createLineString((Coordinate[]) coordList.toArray(
                        new Coordinate[] {  }));

            return line;
        }

        if (childName.equalsIgnoreCase("gml:point")) {
            LOGGER.finer("point");
            type = GML_POINT;
            coordList = parseCoords(child);

            com.vividsolutions.jts.geom.Point point = null;
            point = gfac.createPoint((Coordinate) coordList.get(0));

            return point;
        }

        if (childName.toLowerCase().startsWith("gml:multipolygon")
        || childName.toLowerCase().startsWith("gml:multilinestring")
        || childName.toLowerCase().startsWith("gml:multipoint")) {
         
          List multi = new ArrayList();

            // parse all children thru parseGML
            NodeList kids = child.getChildNodes();

            for (int i = 0; i < kids.getLength(); i++) {
              if ( kids.item(i).getNodeType() == Node.ELEMENT_NODE ) {
                multi.add(parseGML(kids.item(i)))
              }
            }
           
            if ( childName.toLowerCase().startsWith("gml:multipolygon") ) {
              LOGGER.finer( "MultiPolygon" );
              return gfac.createMultiPolygon((Polygon[]) multi.toArray(
                        new Polygon[0]));
            }
            else if ( childName.toLowerCase().startsWith("gml:multilinestring") ) {
              LOGGER.finer( "MultiLineString" );
              return gfac.createMultiLineString((LineString[]) multi.toArray(
                        new LineString[0]));
            }
            else {
              LOGGER.finer( "MultiPoint" );
              return gfac.createMultiPoint((Point[])multi.toArray(new Point[0]) );
            }
           

        }

        return null;
    }

    /**
     * Parse a DOM node into a coordiante list.
     *
     * @deprecated please use ExpressionDOMParser.coords()
     * @param root the root node representation of gml:coordinates.
     * @return the coordinates in a list.
     */
    public static java.util.List parseCoords(Node root) {
      ExpressionDOMParser parser = new ExpressionDOMParser();
      return parser.coords( root );
    }
    /**
     * Parses a dom node into a coordinate list.
     *
     * @param root the root node representation of gml:coordinates.
     * @return the coordinates in a list.
     */
    public java.util.List coords(Node root) {
        LOGGER.finer("parsing coordinate(s) " + root);

        List clist = new ArrayList();
        NodeList kids = root.getChildNodes();

        for (int i = 0; i < kids.getLength(); i++) {
            Node child = kids.item(i);
            LOGGER.finer("doing " + child);

            //if (child.getLocalName().equalsIgnoreCase("gml:coordinate")) {
            //  String internal = child.getNodeValue();
            //}
            String childName = child.getNodeName();
            if(childName == null)
            {
                childName = child.getLocalName();
            }
         if(!childName.startsWith("gml:"))
         {
                    childName = "gml:" + childName;
            }
            if (childName.equalsIgnoreCase("gml:coord"))
            {
              //DJB: adding support for:
              //<gml:coord><gml:X>-180.0</gml:X><gml:Y>-90.0</gml:Y></gml:coord>
        //<gml:coord><gml:X>180.0</gml:X><gml:Y>90.0</gml:Y></gml:coord>
              Coordinate c = new Coordinate();
              NodeList grandChildren = child.getChildNodes();

                for (int t = 0; t < grandChildren.getLength(); t++)
                {
                  Node grandChild = grandChildren.item(t);
                  String grandChildName = grandChild.getNodeName();
                    if(grandChildName == null)
                      grandChildName = grandChild.getLocalName();
                 if(!grandChildName.startsWith("gml:"))
                   grandChildName = "gml:" + grandChildName;
                   
                   if (grandChildName.equalsIgnoreCase("gml:x"))
                   {
                     c.x = Double.parseDouble(grandChild.getChildNodes().item(0).getNodeValue().trim());
                   }
                   else if (grandChildName.equalsIgnoreCase("gml:y"))
                   {
                     c.y = Double.parseDouble(grandChild.getChildNodes().item(0).getNodeValue().trim());
                   }
                  else if (grandChildName.equalsIgnoreCase("gml:z"))
                  {
                    c.z = Double.parseDouble(grandChild.getChildNodes().item(0).getNodeValue().trim());
                  }
                }
                clist.add(c);
            }
          

            if (childName.equalsIgnoreCase("gml:coordinates")) {
                LOGGER.finer("coordinates "
                    + child.getFirstChild().getNodeValue());

                NodeList grandKids = child.getChildNodes();

                for (int k = 0; k < grandKids.getLength(); k++) {
                    Node grandKid = grandKids.item(k);

                    if (grandKid.getNodeValue() == null) {
                        continue;
                    }

                    if (grandKid.getNodeValue().trim().length() == 0) {
                        continue;
                    }

                    String outer = grandKid.getNodeValue().trim();
                    //handle newline and tab whitespace along with space
                    StringTokenizer ost = new StringTokenizer(outer, " \n\t");

                    while (ost.hasMoreTokens()) {
                        String internal = ost.nextToken();
                        StringTokenizer ist = new StringTokenizer(internal, ",");
                        double xCoord = Double.parseDouble(ist.nextToken());
                        double yCoord = Double.parseDouble(ist.nextToken());
                        double zCoord = Double.NaN;

                        if (ist.hasMoreTokens()) {
                            zCoord = Double.parseDouble(ist.nextToken());
                        }

                        clist.add(new Coordinate(xCoord, yCoord, zCoord));
                    }
                }
            }
        }

        return clist;
    }
}
TOP

Related Classes of org.geotools.filter.ExpressionDOMParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.