FileDocCategorySizeDatePackage
XPathMatcher.javaAPI DocApache Xerces 3.0.120321Fri Sep 14 20:33:52 BST 2007org.apache.xerces.impl.xs.identity

XPathMatcher

public class XPathMatcher extends Object
XPath matcher.
xerces.internal
author
Andy Clark, IBM
version
$Id: XPathMatcher.java 572110 2007-09-02 19:04:44Z mrglavas $

Fields Summary
protected static final boolean
DEBUG_ALL
Compile to true to debug everything.
protected static final boolean
DEBUG_METHODS
Compile to true to debug method callbacks.
protected static final boolean
DEBUG_METHODS2
Compile to true to debug important method callbacks.
protected static final boolean
DEBUG_METHODS3
Compile to true to debug the really important methods.
protected static final boolean
DEBUG_MATCH
Compile to true to debug match.
protected static final boolean
DEBUG_STACK
Compile to true to debug step index stack.
protected static final boolean
DEBUG_ANY
Don't touch this value unless you add more debug constants.
protected static final int
MATCHED
protected static final int
MATCHED_ATTRIBUTE
protected static final int
MATCHED_DESCENDANT
protected static final int
MATCHED_DESCENDANT_PREVIOUS
private final XPath.LocationPath[]
fLocationPaths
XPath location path.
private final int[]
fMatched
True if XPath has been matched.
protected Object
fMatchedString
The matching string.
private final org.apache.xerces.util.IntStack[]
fStepIndexes
Integer stack of step indexes.
private final int[]
fCurrentStep
Current step.
private final int[]
fNoMatchDepth
No match depth. The value of this field will be zero while matching is successful for the given xpath expression.
final org.apache.xerces.xni.QName
fQName
Constructors Summary
public XPathMatcher(org.apache.xerces.impl.xpath.XPath xpath)
Constructs an XPath matcher that implements a document fragment handler.

param
xpath The xpath.



    //
    // Constructors
    //

                         
       
        fLocationPaths = xpath.getLocationPaths();
        fStepIndexes = new IntStack[fLocationPaths.length];
        for(int i=0; i<fStepIndexes.length; i++) fStepIndexes[i] = new IntStack();
        fCurrentStep = new int[fLocationPaths.length];
        fNoMatchDepth = new int[fLocationPaths.length];
        fMatched = new int[fLocationPaths.length];        
    
Methods Summary
public voidendElement(org.apache.xerces.xni.QName element, org.apache.xerces.xs.XSTypeDefinition type, boolean nillable, java.lang.Object value, short valueType, org.apache.xerces.xs.ShortList itemValueType)

param
element name of the element.
param
type content type of this element. IOW, the XML schema type of the value. Note that this may not be the type declared in the element declaration, but it is "the actual type". For example, if the XML is <foo xsi:type="xs:string">aaa</foo>, this parameter will be "xs:string".
param
nillable - nillable true if the element declaration is nillable.
param
value - actual value the typed value of the content of this element.

        if (DEBUG_METHODS2) {
            System.out.println(toString()+"#endElement("+
                               "element={"+element+"},"+
                               ")");
        }
        for (int i = 0; i < fLocationPaths.length; i++) {
            // go back a step
            fCurrentStep[i] = fStepIndexes[i].pop();

            // don't do anything, if not matching
            if (fNoMatchDepth[i] > 0) {
                fNoMatchDepth[i]--;
            }

            // signal match, if appropriate
            else {
                int j = 0;
                for(; j < i && ((fMatched[j] & MATCHED) != MATCHED); j++);
                if ((j < i) || (fMatched[j] == 0)) {
                    continue;
                }
                if ((fMatched[j] & MATCHED_ATTRIBUTE) == MATCHED_ATTRIBUTE) {
                    fMatched[i] = 0;
                    continue;
                }
                // only certain kinds of matchers actually
                // match element content.  This permits
                // them a way to override this to do nothing
                // and hopefully save a few operations.
                handleContent(type, nillable, value, valueType, itemValueType);
                fMatched[i] = 0;
            }

            if (DEBUG_STACK) {
                System.out.println(toString()+": "+fStepIndexes[i]);
            }
        }

    
protected voidhandleContent(org.apache.xerces.xs.XSTypeDefinition type, boolean nillable, java.lang.Object value, short valueType, org.apache.xerces.xs.ShortList itemValueType)

 
    
public booleanisMatched()
Returns value of first member of fMatched that is nonzero.

        // xpath has been matched if any one of the members of the union have matched.
        for (int i=0; i < fLocationPaths.length; i++) 
            if (((fMatched[i] & MATCHED) == MATCHED) 
                    && ((fMatched[i] & MATCHED_DESCENDANT_PREVIOUS) != MATCHED_DESCENDANT_PREVIOUS) 
                    && ((fNoMatchDepth[i] == 0)
                    || ((fMatched[i] & MATCHED_DESCENDANT) == MATCHED_DESCENDANT))) 
                return true;

        return false;
    
protected voidmatched(java.lang.Object actualValue, short valueType, org.apache.xerces.xs.ShortList itemValueType, boolean isNil)
This method is called when the XPath handler matches the XPath expression. Subclasses can override this method to provide default handling upon a match.

        if (DEBUG_METHODS3) {
            System.out.println(toString()+"#matched(\""+actualValue+"\")");
        }
    
private static booleanmatches(XPath.NodeTest nodeTest, org.apache.xerces.xni.QName value)
Returns true if the given QName matches the node test.

        if (nodeTest.type == XPath.NodeTest.QNAME) {
            return nodeTest.name.equals(value);
        }
        if (nodeTest.type == XPath.NodeTest.NAMESPACE) {
            return nodeTest.name.uri == value.uri;
        }
        // XPath.NodeTest.WILDCARD
        return true;
    
private java.lang.Stringnormalize(java.lang.String s)
Normalizes text.

        StringBuffer str = new StringBuffer();
        int length = s.length();
        for (int i = 0; i < length; i++) {
            char c = s.charAt(i);
            switch (c) {
                case '\n": {
                    str.append("\\n");
                    break;
                }
                default: {
                    str.append(c);
                }
            }
        }
        return str.toString();
    
public voidstartDocumentFragment()
The start of the document fragment.

        if (DEBUG_METHODS) {
            System.out.println(toString()+"#startDocumentFragment("+
                               ")");
        }

        // reset state
        fMatchedString = null;
        for(int i = 0; i < fLocationPaths.length; i++) {
            fStepIndexes[i].clear();
            fCurrentStep[i] = 0;
            fNoMatchDepth[i] = 0;
            fMatched[i] = 0;
        }


    
public voidstartElement(org.apache.xerces.xni.QName element, org.apache.xerces.xni.XMLAttributes attributes)
The start of an element. If the document specifies the start element by using an empty tag, then the startElement method will immediately be followed by the endElement method, with no intervening methods.

param
element The name of the element.
param
attributes The element attributes.
throws
SAXException Thrown by handler to signal an error.

        if (DEBUG_METHODS2) {
            System.out.println(toString()+"#startElement("+
                               "element={"+element+"},"+
                               "attributes=..."+attributes+
                               ")");                     
        }

        for (int i = 0; i < fLocationPaths.length; i++) {
            // push context
            int startStep = fCurrentStep[i];
            fStepIndexes[i].push(startStep);

            // try next xpath, if not matching
            if ((fMatched[i] & MATCHED_DESCENDANT) == MATCHED || fNoMatchDepth[i] > 0) {
                fNoMatchDepth[i]++;
                continue;
            }
            if((fMatched[i] & MATCHED_DESCENDANT) == MATCHED_DESCENDANT) {
                fMatched[i] = MATCHED_DESCENDANT_PREVIOUS;
            }

            if (DEBUG_STACK) {
                System.out.println(toString()+": "+fStepIndexes[i]);
            }

            // consume self::node() steps
            XPath.Step[] steps = fLocationPaths[i].steps;
            while (fCurrentStep[i] < steps.length &&
                    steps[fCurrentStep[i]].axis.type == XPath.Axis.SELF) {
                if (DEBUG_MATCH) {
                    XPath.Step step = steps[fCurrentStep[i]];
                    System.out.println(toString()+" [SELF] MATCHED!");
                }
                fCurrentStep[i]++;
            }
            if (fCurrentStep[i] == steps.length) {
                if (DEBUG_MATCH) {
                    System.out.println(toString()+" XPath MATCHED!");
                }
                fMatched[i] = MATCHED;
                continue;
            }

            // now if the current step is a descendant step, we let the next
            // step do its thing; if it fails, we reset ourselves
            // to look at this step for next time we're called.
            // so first consume all descendants:
            int descendantStep = fCurrentStep[i];
            while(fCurrentStep[i] < steps.length && steps[fCurrentStep[i]].axis.type == XPath.Axis.DESCENDANT) {
                if (DEBUG_MATCH) {
                    XPath.Step step = steps[fCurrentStep[i]];
                    System.out.println(toString()+" [DESCENDANT] MATCHED!");
                }
                fCurrentStep[i]++;
            }
            boolean sawDescendant = fCurrentStep[i] > descendantStep;
            if (fCurrentStep[i] == steps.length) {
                if (DEBUG_MATCH) {
                    System.out.println(toString()+" XPath DIDN'T MATCH!");
                }
                fNoMatchDepth[i]++;
                if (DEBUG_MATCH) {
                    System.out.println(toString()+" [CHILD] after NO MATCH");
                }
                continue;
            }

            // match child::... step, if haven't consumed any self::node()
            if ((fCurrentStep[i] == startStep || fCurrentStep[i] > descendantStep) &&
                steps[fCurrentStep[i]].axis.type == XPath.Axis.CHILD) {
                XPath.Step step = steps[fCurrentStep[i]];
                XPath.NodeTest nodeTest = step.nodeTest;
                if (DEBUG_MATCH) {
                    System.out.println(toString()+" [CHILD] before");
                }
                if (!matches(nodeTest, element)) {
                    if (fCurrentStep[i] > descendantStep) {
                        fCurrentStep[i] = descendantStep;
                        continue;
                    }
                    fNoMatchDepth[i]++;
                    if (DEBUG_MATCH) {
                        System.out.println(toString()+" [CHILD] after NO MATCH");
                    }
                    continue;
                }
                fCurrentStep[i]++;
                if (DEBUG_MATCH) {
                    System.out.println(toString()+" [CHILD] after MATCHED!");
                }
            }
            if (fCurrentStep[i] == steps.length) {
                if (sawDescendant) {
                    fCurrentStep[i] = descendantStep;
                    fMatched[i] = MATCHED_DESCENDANT;
                } 
                else {
                    fMatched[i] = MATCHED;
                }
                continue;
            }

            // match attribute::... step
            if (fCurrentStep[i] < steps.length &&
                steps[fCurrentStep[i]].axis.type == XPath.Axis.ATTRIBUTE) {
                if (DEBUG_MATCH) {
                    System.out.println(toString()+" [ATTRIBUTE] before");
                }
                int attrCount = attributes.getLength();
                if (attrCount > 0) {
                    XPath.NodeTest nodeTest = steps[fCurrentStep[i]].nodeTest;

                    for (int aIndex = 0; aIndex < attrCount; aIndex++) {
                        attributes.getName(aIndex, fQName);
                        if (matches(nodeTest, fQName)) {
                            fCurrentStep[i]++;
                            if (fCurrentStep[i] == steps.length) {
                                fMatched[i] = MATCHED_ATTRIBUTE;
                                int j = 0;
                                for(; j < i && ((fMatched[j] & MATCHED) != MATCHED); j++);
                                if (j == i) {
                                    AttributePSVI attrPSVI = (AttributePSVI)attributes.getAugmentations(aIndex).getItem(Constants.ATTRIBUTE_PSVI);
                                    fMatchedString = attrPSVI.getActualNormalizedValue();
                                    matched(fMatchedString, attrPSVI.getActualNormalizedValueType(), attrPSVI.getItemValueTypes(), false);
                                }
                            }
                            break;
                        }
                    }
                }
                if ((fMatched[i] & MATCHED) != MATCHED) {
                    if(fCurrentStep[i] > descendantStep) {
                        fCurrentStep[i] = descendantStep;
                        continue;
                    }
                    fNoMatchDepth[i]++;
                    if (DEBUG_MATCH) {
                        System.out.println(toString()+" [ATTRIBUTE] after");
                    }
                    continue;
                }
                if (DEBUG_MATCH) {
                    System.out.println(toString()+" [ATTRIBUTE] after MATCHED!");
                }
            }
        }

    
public java.lang.StringtoString()
Returns a string representation of this object.

        /***
        return fLocationPath.toString();
        /***/
        StringBuffer str = new StringBuffer();
        String s = super.toString();
        int index2 = s.lastIndexOf('.");
        if (index2 != -1) {
            s = s.substring(index2 + 1);
        }
        str.append(s);
        for(int i =0;i<fLocationPaths.length; i++) {
            str.append('[");
            XPath.Step[] steps = fLocationPaths[i].steps;
            for (int j = 0; j < steps.length; j++) {
                if (j == fCurrentStep[i]) {
                    str.append('^");
                }
                str.append(steps[j].toString());
                if (j < steps.length - 1) {
                    str.append('/");
                }
            }
            if (fCurrentStep[i] == steps.length) {
                str.append('^");
            }
            str.append(']");
            str.append(',");
        }
        return str.toString();