    001    /*
    002     * Copyright (c) 2007-2014 Concurrent, Inc. All Rights Reserved.
    003     *
    004     * Project and contact information: http://www.cascading.org/
    005     *
    006     * This file is part of the Cascading project.
    007     *
    008     * Licensed under the Apache License, Version 2.0 (the "License");
    009     * you may not use this file except in compliance with the License.
    010     * You may obtain a copy of the License at
    011     *
    012     *     http://www.apache.org/licenses/LICENSE-2.0
    013     *
    014     * Unless required by applicable law or agreed to in writing, software
    015     * distributed under the License is distributed on an "AS IS" BASIS,
    016     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    017     * See the License for the specific language governing permissions and
    018     * limitations under the License.
    019     */
    020
    021    package cascading.operation.xml;
    022
    023    import javax.xml.parsers.DocumentBuilder;
    024    import javax.xml.xpath.XPathConstants;
    025    import javax.xml.xpath.XPathExpression;
    026    import javax.xml.xpath.XPathExpressionException;
    027
    028    import cascading.flow.FlowProcess;
    029    import cascading.operation.Filter;
    030    import cascading.operation.FilterCall;
    031    import cascading.operation.OperationException;
    032    import cascading.tuple.Tuple;
    033    import cascading.util.Pair;
    034    import org.slf4j.Logger;
    035    import org.slf4j.LoggerFactory;
    036    import org.w3c.dom.Document;
    037
    038    /**
    039     * XPathFilter will filter out a Tuple if the given XPath expression returns false. Set removeMatch to true
    040     * if the filter should be reversed.
    041     */
    042    public class XPathFilter extends XPathOperation implements Filter<Pair<DocumentBuilder, Tuple>>
    043      {
    044      /** Field LOG */
    045      private static final Logger LOG = LoggerFactory.getLogger( XPathFilter.class );
    046
    047      /** Field removeMatch */
    048      private boolean removeMatch = false;
    049
    050      /**
    051       * Constructor XPathFilter creates a new XPathFilter instance.
    052       *
    053       * @param namespaces of type String[][]
    054       * @param path       of type String
    055       */
    056      public XPathFilter( String[][] namespaces, String path )
    057        {
    058        super( 1, namespaces, path );
    059        }
    060
    061      /**
    062       * Constructor XPathFilter creates a new XPathFilter instance.
    063       *
    064       * @param removeMatch of type boolean
    065       * @param namespaces  of type String[][]
    066       * @param path        of type String
    067       */
    068      public XPathFilter( boolean removeMatch, String[][] namespaces, String path )
    069        {
    070        super( 1, namespaces, path );
    071        this.removeMatch = removeMatch;
    072        }
    073
    074      @Override
    075      public boolean isRemove( FlowProcess flowProcess, FilterCall<Pair<DocumentBuilder, Tuple>> filterCall )
    076        {
    077        String argument = filterCall.getArguments().getString( 0 );
    078        Document document = parseDocument( filterCall.getContext().getLhs(), argument );
    079        XPathExpression expression = getExpressions().get( 0 );
    080
    081        try
    082          {
    083          boolean value = (Boolean) expression.evaluate( document, XPathConstants.BOOLEAN );
    084
    085          LOG.debug( "xpath: {} matches: {}", paths[ 0 ], value );
    086
    087          return value == removeMatch;
    088          }
    089        catch( XPathExpressionException exception )
    090          {
    091          throw new OperationException( "could not evaluate xpath expression: " + paths[ 0 ], exception );
    092          }
    093        }
    094      }