XPathMatcherpublic class XPathMatcher extends Object
Fields Summary |
---|
protected static final boolean | DEBUG_ALLCompile to true to debug everything. | protected static final boolean | DEBUG_METHODSCompile to true to debug method callbacks. | protected static final boolean | DEBUG_METHODS2Compile to true to debug important method callbacks. | protected static final boolean | DEBUG_METHODS3Compile to true to debug the really important methods. | protected static final boolean | DEBUG_MATCHCompile to true to debug match. | protected static final boolean | DEBUG_STACKCompile to true to debug step index stack. | protected static final boolean | DEBUG_ANYDon'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[] | fLocationPathsXPath location path. | private final int[] | fMatchedTrue if XPath has been matched. | protected Object | fMatchedStringThe matching string. | private final org.apache.xerces.util.IntStack[] | fStepIndexesInteger stack of step indexes. | private final int[] | fCurrentStepCurrent step. | private final int[] | fNoMatchDepthNo 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.
//
// 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 void | endElement(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)
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 void | handleContent(org.apache.xerces.xs.XSTypeDefinition type, boolean nillable, java.lang.Object value, short valueType, org.apache.xerces.xs.ShortList itemValueType)
| public boolean | isMatched()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 void | matched(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 boolean | matches(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.String | normalize(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 void | startDocumentFragment()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 void | startElement(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.
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.String | toString()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();
|
|