View Javadoc

    1   /*
    2    * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/pattern/LocationPathPattern.java,v 1.14 2005/06/28 13:44:44 elharo Exp $
    3    * $Revision: 1.14 $
    4    * $Date: 2005/06/28 13:44:44 $
    5    *
    6    * ====================================================================
    7    *
    8    * Copyright (C) 2000-2002 bob mcwhirter & James Strachan.
    9    * All rights reserved.
    10   *
    11   * Redistribution and use in source and binary forms, with or without
    12   * modification, are permitted provided that the following conditions
    13   * are met:
    14   *
    15   * 1. Redistributions of source code must retain the above copyright
    16   *    notice, this list of conditions, and the following disclaimer.
    17   *
    18   * 2. Redistributions in binary form must reproduce the above copyright
    19   *    notice, this list of conditions, and the disclaimer that follows
    20   *    these conditions in the documentation and/or other materials
    21   *    provided with the distribution.
    22   *
    23   * 3. The name "Jaxen" must not be used to endorse or promote products
    24   *    derived from this software without prior written permission.  For
    25   *    written permission, please contact license@jaxen.org.
    26   *
    27   * 4. Products derived from this software may not be called "Jaxen", nor
    28   *    may "Jaxen" appear in their name, without prior written permission
    29   *    from the Jaxen Project Management (pm@jaxen.org).
    30   *
    31   * In addition, we request (but do not require) that you include in the
    32   * end-user documentation provided with the redistribution and/or in the
    33   * software itself an acknowledgement equivalent to the following:
    34   *     "This product includes software developed by the
    35   *      Jaxen Project <http://www.jaxen.org/>."
    36   * Alternatively, the acknowledgment may be graphical using the logos
    37   * available at http://www.jaxen.org/
    38   *
    39   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
    40   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    41   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    42   * DISCLAIMED.  IN NO EVENT SHALL THE Jaxen AUTHORS OR THE PROJECT
    43   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    44   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    45   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
    46   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    47   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    48   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    49   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    50   * SUCH DAMAGE.
    51   *
    52   * ====================================================================
    53   * This software consists of voluntary contributions made by many
    54   * individuals on behalf of the Jaxen Project and was originally
    55   * created by bob mcwhirter <bob@werken.com> and
    56   * James Strachan <jstrachan@apache.org>.  For more information on the
    57   * Jaxen Project, please see <http://www.jaxen.org/>.
    58   *
    59   * $Id: LocationPathPattern.java,v 1.14 2005/06/28 13:44:44 elharo Exp $
    60   */
    61
    62  package org.jaxen.pattern;
    63
    64  import java.util.ArrayList;
    65  import java.util.Iterator;
    66  import java.util.List;
    67
    68  import org.jaxen.Context;
    69  import org.jaxen.JaxenException;
    70  import org.jaxen.Navigator;
    71  import org.jaxen.expr.FilterExpr;
    72  import org.jaxen.util.SingletonList;
    73
    74  /*** <p><code>LocationPathPattern</code> matches any node using a
    75    * location path such as A/B/C.
    76    * The parentPattern and ancestorPattern properties are used to
    77    * chain location path patterns together</p>
    78    *
    79    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
    80    * @version $Revision: 1.14 $
    81    */
    82  public class LocationPathPattern extends Pattern {
    83
    84      /*** The node test to perform on this step of the path */
    85      private NodeTest nodeTest = AnyNodeTest.getInstance();
    86
    87      /*** Patterns matching my parent node */
    88      private Pattern parentPattern;
    89
    90      /*** Patterns matching one of my ancestors */
    91      private Pattern ancestorPattern;
    92
    93      /*** The filters to match against */
    94      private List filters;
    95
    96      /*** Whether this lcoation path is absolute or not */
    97      private boolean absolute;
    98
    99
    100     public LocationPathPattern()
    101     {
    102     }
    103
    104     public LocationPathPattern(NodeTest nodeTest)
    105     {
    106         this.nodeTest = nodeTest;
    107     }
    108
    109     public Pattern simplify()
    110     {
    111         if ( parentPattern != null )
    112         {
    113             parentPattern = parentPattern.simplify();
    114         }
    115         if ( ancestorPattern != null )
    116         {
    117             ancestorPattern = ancestorPattern.simplify();
    118         }
    119         if ( filters == null )
    120         {
    121             if ( parentPattern == null && ancestorPattern == null )
    122             {
    123                 return nodeTest;
    124             }
    125             if ( parentPattern != null && ancestorPattern == null )
    126             {
    127                 if ( nodeTest instanceof AnyNodeTest )
    128                 {
    129                     return parentPattern;
    130                 }
    131             }
    132         }
    133         return this;
    134     }
    135
    136     /*** Adds a filter to this pattern
    137      */
    138     public void addFilter(FilterExpr filter)
    139     {
    140         if ( filters == null )
    141         {
    142             filters = new ArrayList();
    143         }
    144         filters.add( filter );
    145     }
    146
    147     /*** Adds a pattern for the parent of the current
    148      * context node used in this pattern.
    149      */
    150     public void setParentPattern(Pattern parentPattern)
    151     {
    152         this.parentPattern = parentPattern;
    153     }
    154
    155     /*** Adds a pattern for an ancestor of the current
    156      * context node used in this pattern.
    157      */
    158     public void setAncestorPattern(Pattern ancestorPattern)
    159     {
    160         this.ancestorPattern = ancestorPattern;
    161     }
    162
    163     /*** Allows the NodeTest to be set
    164      */
    165     public void setNodeTest(NodeTest nodeTest) throws JaxenException
    166     {
    167         if ( this.nodeTest instanceof AnyNodeTest )
    168         {
    169             this.nodeTest = nodeTest;
    170         }
    171         else
    172         {
    173             throw new JaxenException( "Attempt to overwrite nodeTest: " + this.nodeTest + " with: " + nodeTest );
    174         }
    175     }
    176
    177     /*** @return true if the pattern matches the given node
    178       */
    179     public boolean matches( Object node, Context context ) throws JaxenException
    180     {
    181         Navigator navigator = context.getNavigator();
    182
    183 /*
    184         if ( isAbsolute() )
    185         {
    186             node = navigator.getDocumentNode( node );
    187         }
    188 */
    189         if (! nodeTest.matches(node, context) )
    190         {
    191             return false;
    192         }
    193
    194         if (parentPattern != null)
    195         {
    196             Object parent = navigator.getParentNode( node );
    197             if ( parent == null )
    198             {
    199                 return false;
    200             }
    201             if ( ! parentPattern.matches( parent, context ) )
    202             {
    203                 return false;
    204             }
    205         }
    206
    207         if (ancestorPattern != null) {
    208             Object ancestor = navigator.getParentNode( node );
    209             while (true)
    210             {
    211                 if ( ancestorPattern.matches( ancestor, context ) )
    212                 {
    213                     break;
    214                 }
    215                 if ( ancestor == null )
    216                 {
    217                     return false;
    218                 }
    219                 if ( navigator.isDocument( ancestor ) )
    220                 {
    221                     return false;
    222                 }
    223                 ancestor = navigator.getParentNode( ancestor );
    224             }
    225         }
    226
    227         if (filters != null)
    228         {
    229             List list = new SingletonList(node);
    230
    231             context.setNodeSet( list );
    232
    233             // XXXX: filters aren't positional, so should we clone context?
    234
    235             boolean answer = true;
    236
    237             for (Iterator iter = filters.iterator(); iter.hasNext(); )
    238             {
    239                 FilterExpr filter = (FilterExpr) iter.next();
    240
    241                 if ( ! filter.asBoolean( context ) )
    242                 {
    243                     answer = false;
    244                     break;
    245                 }
    246             }
    247             // restore context
    248
    249             context.setNodeSet( list );
    250
    251             return answer;
    252         }
    253         return true;
    254     }
    255
    256     public double getPriority()
    257     {
    258         if ( filters != null )
    259         {
    260             return 0.5;
    261         }
    262         return nodeTest.getPriority();
    263     }
    264
    265
    266     public short getMatchType()
    267     {
    268         return nodeTest.getMatchType();
    269     }
    270
    271     public String getText()
    272     {
    273         StringBuffer buffer = new StringBuffer();
    274         if ( absolute )
    275         {
    276             buffer.append( "/" );
    277         }
    278         if (ancestorPattern != null)
    279         {
    280             String text = ancestorPattern.getText();
    281             if ( text.length() > 0 )
    282             {
    283                 buffer.append( text );
    284                 buffer.append( "//" );
    285             }
    286         }
    287         if (parentPattern != null)
    288         {
    289             String text = parentPattern.getText();
    290             if ( text.length() > 0 )
    291             {
    292                 buffer.append( text );
    293                 buffer.append( "/" );
    294             }
    295         }
    296         buffer.append( nodeTest.getText() );
    297
    298         if ( filters != null )
    299         {
    300             buffer.append( "[" );
    301             for (Iterator iter = filters.iterator(); iter.hasNext(); )
    302             {
    303                 FilterExpr filter = (FilterExpr) iter.next();
    304                 buffer.append( filter.getText() );
    305             }
    306             buffer.append( "]" );
    307         }
    308         return buffer.toString();
    309     }
    310
    311     public String toString()
    312     {
    313         return super.toString() + "[ absolute: " + absolute + " parent: " + parentPattern + " ancestor: "
    314             + ancestorPattern + " filters: " + filters + " nodeTest: "
    315             + nodeTest + " ]";
    316     }
    317
    318     public boolean isAbsolute()
    319     {
    320         return absolute;
    321     }
    322
    323     public void setAbsolute(boolean absolute)
    324     {
    325         this.absolute = absolute;
    326     }
    327
    328     public boolean hasAnyNodeTest()
    329     {
    330         return nodeTest instanceof AnyNodeTest;
    331     }
    332
    333 }