/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the  "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * $Id: NodeTest.java 468655 2006-10-28 07:12:06Z minchau $
 */
package org.apache.xpath.patterns;

import org.apache.xml.dtm.DTM;
import org.apache.xml.dtm.DTMFilter;
import org.apache.xpath.Expression;
import org.apache.xpath.ExpressionOwner;
import org.apache.xpath.XPath;
import org.apache.xpath.XPathContext;
import org.apache.xpath.XPathVisitor;
import org.apache.xpath.objects.XNumber;
import org.apache.xpath.objects.XObject;

This is the basic node test class for both match patterns and location path steps.
@xsl.usageadvanced
/** * This is the basic node test class for both match patterns and location path * steps. * @xsl.usage advanced */
public class NodeTest extends Expression { static final long serialVersionUID = -5736721866747906182L;
The namespace or local name for node tests with a wildcard. @see the XPath NameTest production.
/** * The namespace or local name for node tests with a wildcard. * @see <a href="http://www.w3.org/TR/xpath#NT-NameTest">the XPath NameTest production.</a> */
public static final String WILD = "*";
The URL to pass to the Node#supports method, to see if the DOM has already been stripped of whitespace nodes.
/** * The URL to pass to the Node#supports method, to see if the * DOM has already been stripped of whitespace nodes. */
public static final String SUPPORTS_PRE_STRIPPING = "http://xml.apache.org/xpath/features/whitespace-pre-stripping";
This attribute determines which node types are accepted.
@serial
/** * This attribute determines which node types are accepted. * @serial */
protected int m_whatToShow;
Special bitmap for match patterns starting with a function. Make sure this does not conflict with NodeFilter.
/** * Special bitmap for match patterns starting with a function. * Make sure this does not conflict with {@link org.w3c.dom.traversal.NodeFilter}. */
public static final int SHOW_BYFUNCTION = 0x00010000;
This attribute determines which node types are accepted. These constants are defined in the NodeFilter interface.
Returns:bitset mainly defined in NodeFilter.
/** * This attribute determines which node types are accepted. * These constants are defined in the {@link org.w3c.dom.traversal.NodeFilter} * interface. * * @return bitset mainly defined in {@link org.w3c.dom.traversal.NodeFilter}. */
public int getWhatToShow() { return m_whatToShow; }
This attribute determines which node types are accepted. These constants are defined in the NodeFilter interface.
Params:
/** * This attribute determines which node types are accepted. * These constants are defined in the {@link org.w3c.dom.traversal.NodeFilter} * interface. * * @param what bitset mainly defined in {@link org.w3c.dom.traversal.NodeFilter}. */
public void setWhatToShow(int what) { m_whatToShow = what; }
The namespace to be tested for, which may be null. @serial
/** * The namespace to be tested for, which may be null. * @serial */
String m_namespace;
Return the namespace to be tested.
Returns:The namespace to be tested for, or WILD, or null.
/** * Return the namespace to be tested. * * @return The namespace to be tested for, or {@link #WILD}, or null. */
public String getNamespace() { return m_namespace; }
Set the namespace to be tested.
Params:
  • ns – The namespace to be tested for, or WILD, or null.
/** * Set the namespace to be tested. * * @param ns The namespace to be tested for, or {@link #WILD}, or null. */
public void setNamespace(String ns) { m_namespace = ns; }
The local name to be tested for. @serial
/** * The local name to be tested for. * @serial */
protected String m_name;
Return the local name to be tested.
Returns:the local name to be tested, or WILD, or an empty string.
/** * Return the local name to be tested. * * @return the local name to be tested, or {@link #WILD}, or an empty string. */
public String getLocalName() { return (null == m_name) ? "" : m_name; }
Set the local name to be tested.
Params:
  • name – the local name to be tested, or WILD, or an empty string.
/** * Set the local name to be tested. * * @param name the local name to be tested, or {@link #WILD}, or an empty string. */
public void setLocalName(String name) { m_name = name; }
Statically calculated score for this test. One of SCORE_NODETEST, SCORE_NONE, SCORE_NSWILD, SCORE_QNAME, or SCORE_OTHER. @serial
/** * Statically calculated score for this test. One of * {@link #SCORE_NODETEST}, * {@link #SCORE_NONE}, * {@link #SCORE_NSWILD}, * {@link #SCORE_QNAME}, or * {@link #SCORE_OTHER}. * @serial */
XNumber m_score;
The match score if the pattern consists of just a NodeTest. @see XSLT Specification - 5.5 Conflict Resolution for Template Rules
/** * The match score if the pattern consists of just a NodeTest. * @see <a href="http://www.w3.org/TR/xslt#conflict">XSLT Specification - 5.5 Conflict Resolution for Template Rules</a> */
public static final XNumber SCORE_NODETEST = new XNumber(XPath.MATCH_SCORE_NODETEST);
The match score if the pattern pattern has the form NCName:*. @see XSLT Specification - 5.5 Conflict Resolution for Template Rules
/** * The match score if the pattern pattern has the form NCName:*. * @see <a href="http://www.w3.org/TR/xslt#conflict">XSLT Specification - 5.5 Conflict Resolution for Template Rules</a> */
public static final XNumber SCORE_NSWILD = new XNumber(XPath.MATCH_SCORE_NSWILD);
The match score if the pattern has the form of a QName optionally preceded by an @ character. @see XSLT Specification - 5.5 Conflict Resolution for Template Rules
/** * The match score if the pattern has the form * of a QName optionally preceded by an @ character. * @see <a href="http://www.w3.org/TR/xslt#conflict">XSLT Specification - 5.5 Conflict Resolution for Template Rules</a> */
public static final XNumber SCORE_QNAME = new XNumber(XPath.MATCH_SCORE_QNAME);
The match score if the pattern consists of something other than just a NodeTest or just a qname. @see XSLT Specification - 5.5 Conflict Resolution for Template Rules
/** * The match score if the pattern consists of something * other than just a NodeTest or just a qname. * @see <a href="http://www.w3.org/TR/xslt#conflict">XSLT Specification - 5.5 Conflict Resolution for Template Rules</a> */
public static final XNumber SCORE_OTHER = new XNumber(XPath.MATCH_SCORE_OTHER);
The match score if no match is made. @see XSLT Specification - 5.5 Conflict Resolution for Template Rules
/** * The match score if no match is made. * @see <a href="http://www.w3.org/TR/xslt#conflict">XSLT Specification - 5.5 Conflict Resolution for Template Rules</a> */
public static final XNumber SCORE_NONE = new XNumber(XPath.MATCH_SCORE_NONE);
Construct an NodeTest that tests for namespaces and node names.
Params:
  • whatToShow – Bit set defined mainly by NodeFilter.
  • namespace – The namespace to be tested.
  • name – The local name to be tested.
/** * Construct an NodeTest that tests for namespaces and node names. * * * @param whatToShow Bit set defined mainly by {@link org.w3c.dom.traversal.NodeFilter}. * @param namespace The namespace to be tested. * @param name The local name to be tested. */
public NodeTest(int whatToShow, String namespace, String name) { initNodeTest(whatToShow, namespace, name); }
Construct an NodeTest that doesn't test for node names.
Params:
  • whatToShow – Bit set defined mainly by NodeFilter.
/** * Construct an NodeTest that doesn't test for node names. * * * @param whatToShow Bit set defined mainly by {@link org.w3c.dom.traversal.NodeFilter}. */
public NodeTest(int whatToShow) { initNodeTest(whatToShow); }
See Also:
  • deepEquals.deepEquals(Expression)
/** * @see Expression#deepEquals(Expression) */
public boolean deepEquals(Expression expr) { if(!isSameClass(expr)) return false; NodeTest nt = (NodeTest)expr; if(null != nt.m_name) { if(null == m_name) return false; else if(!nt.m_name.equals(m_name)) return false; } else if(null != m_name) return false; if(null != nt.m_namespace) { if(null == m_namespace) return false; else if(!nt.m_namespace.equals(m_namespace)) return false; } else if(null != m_namespace) return false; if(m_whatToShow != nt.m_whatToShow) return false; if(m_isTotallyWild != nt.m_isTotallyWild) return false; return true; }
Null argument constructor.
/** * Null argument constructor. */
public NodeTest(){}
Initialize this node test by setting the whatToShow property, and calculating the score that this test will return if a test succeeds.
Params:
  • whatToShow – Bit set defined mainly by NodeFilter.
/** * Initialize this node test by setting the whatToShow property, and * calculating the score that this test will return if a test succeeds. * * * @param whatToShow Bit set defined mainly by {@link org.w3c.dom.traversal.NodeFilter}. */
public void initNodeTest(int whatToShow) { m_whatToShow = whatToShow; calcScore(); }
Initialize this node test by setting the whatToShow property and the namespace and local name, and calculating the score that this test will return if a test succeeds.
Params:
  • whatToShow – Bit set defined mainly by NodeFilter.
  • namespace – The namespace to be tested.
  • name – The local name to be tested.
/** * Initialize this node test by setting the whatToShow property and the * namespace and local name, and * calculating the score that this test will return if a test succeeds. * * * @param whatToShow Bit set defined mainly by {@link org.w3c.dom.traversal.NodeFilter}. * @param namespace The namespace to be tested. * @param name The local name to be tested. */
public void initNodeTest(int whatToShow, String namespace, String name) { m_whatToShow = whatToShow; m_namespace = namespace; m_name = name; calcScore(); }
True if this test has a null namespace and a local name of WILD. @serial
/** * True if this test has a null namespace and a local name of {@link #WILD}. * @serial */
private boolean m_isTotallyWild;
Get the static score for this node test.
Returns:Should be one of the SCORE_XXX constants.
/** * Get the static score for this node test. * @return Should be one of the SCORE_XXX constants. */
public XNumber getStaticScore() { return m_score; }
Set the static score for this node test.
Params:
  • score – Should be one of the SCORE_XXX constants.
/** * Set the static score for this node test. * @param score Should be one of the SCORE_XXX constants. */
public void setStaticScore(XNumber score) { m_score = score; }
Static calc of match score.
/** * Static calc of match score. */
protected void calcScore() { if ((m_namespace == null) && (m_name == null)) m_score = SCORE_NODETEST; else if (((m_namespace == WILD) || (m_namespace == null)) && (m_name == WILD)) m_score = SCORE_NODETEST; else if ((m_namespace != WILD) && (m_name == WILD)) m_score = SCORE_NSWILD; else m_score = SCORE_QNAME; m_isTotallyWild = (m_namespace == null && m_name == WILD); }
Get the score that this test will return if a test succeeds.
Returns:the score that this test will return if a test succeeds.
/** * Get the score that this test will return if a test succeeds. * * * @return the score that this test will return if a test succeeds. */
public double getDefaultScore() { return m_score.num(); }
Tell what node type to test, if not DTMFilter.SHOW_ALL.
Params:
  • whatToShow – Bit set defined mainly by DTMFilter.
Returns:the node type for the whatToShow. Since whatToShow can specify multiple types, it will return the first bit tested that is on, so the caller of this function should take care that this is the function they really want to call. If none of the known bits are set, this function will return zero.
/** * Tell what node type to test, if not DTMFilter.SHOW_ALL. * * @param whatToShow Bit set defined mainly by * {@link org.apache.xml.dtm.DTMFilter}. * @return the node type for the whatToShow. Since whatToShow can specify * multiple types, it will return the first bit tested that is on, * so the caller of this function should take care that this is * the function they really want to call. If none of the known bits * are set, this function will return zero. */
public static int getNodeTypeTest(int whatToShow) { // %REVIEW% Is there a better way? if (0 != (whatToShow & DTMFilter.SHOW_ELEMENT)) return DTM.ELEMENT_NODE; if (0 != (whatToShow & DTMFilter.SHOW_ATTRIBUTE)) return DTM.ATTRIBUTE_NODE; if (0 != (whatToShow & DTMFilter.SHOW_TEXT)) return DTM.TEXT_NODE; if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT)) return DTM.DOCUMENT_NODE; if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT_FRAGMENT)) return DTM.DOCUMENT_FRAGMENT_NODE; if (0 != (whatToShow & DTMFilter.SHOW_NAMESPACE)) return DTM.NAMESPACE_NODE; if (0 != (whatToShow & DTMFilter.SHOW_COMMENT)) return DTM.COMMENT_NODE; if (0 != (whatToShow & DTMFilter.SHOW_PROCESSING_INSTRUCTION)) return DTM.PROCESSING_INSTRUCTION_NODE; if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT_TYPE)) return DTM.DOCUMENT_TYPE_NODE; if (0 != (whatToShow & DTMFilter.SHOW_ENTITY)) return DTM.ENTITY_NODE; if (0 != (whatToShow & DTMFilter.SHOW_ENTITY_REFERENCE)) return DTM.ENTITY_REFERENCE_NODE; if (0 != (whatToShow & DTMFilter.SHOW_NOTATION)) return DTM.NOTATION_NODE; if (0 != (whatToShow & DTMFilter.SHOW_CDATA_SECTION)) return DTM.CDATA_SECTION_NODE; return 0; }
Do a diagnostics dump of a whatToShow bit set.
Params:
  • whatToShow – Bit set defined mainly by DTMFilter.
/** * Do a diagnostics dump of a whatToShow bit set. * * * @param whatToShow Bit set defined mainly by * {@link org.apache.xml.dtm.DTMFilter}. */
public static void debugWhatToShow(int whatToShow) { java.util.Vector v = new java.util.Vector(); if (0 != (whatToShow & DTMFilter.SHOW_ATTRIBUTE)) v.addElement("SHOW_ATTRIBUTE"); if (0 != (whatToShow & DTMFilter.SHOW_NAMESPACE)) v.addElement("SHOW_NAMESPACE"); if (0 != (whatToShow & DTMFilter.SHOW_CDATA_SECTION)) v.addElement("SHOW_CDATA_SECTION"); if (0 != (whatToShow & DTMFilter.SHOW_COMMENT)) v.addElement("SHOW_COMMENT"); if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT)) v.addElement("SHOW_DOCUMENT"); if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT_FRAGMENT)) v.addElement("SHOW_DOCUMENT_FRAGMENT"); if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT_TYPE)) v.addElement("SHOW_DOCUMENT_TYPE"); if (0 != (whatToShow & DTMFilter.SHOW_ELEMENT)) v.addElement("SHOW_ELEMENT"); if (0 != (whatToShow & DTMFilter.SHOW_ENTITY)) v.addElement("SHOW_ENTITY"); if (0 != (whatToShow & DTMFilter.SHOW_ENTITY_REFERENCE)) v.addElement("SHOW_ENTITY_REFERENCE"); if (0 != (whatToShow & DTMFilter.SHOW_NOTATION)) v.addElement("SHOW_NOTATION"); if (0 != (whatToShow & DTMFilter.SHOW_PROCESSING_INSTRUCTION)) v.addElement("SHOW_PROCESSING_INSTRUCTION"); if (0 != (whatToShow & DTMFilter.SHOW_TEXT)) v.addElement("SHOW_TEXT"); int n = v.size(); for (int i = 0; i < n; i++) { if (i > 0) System.out.print(" | "); System.out.print(v.elementAt(i)); } if (0 == n) System.out.print("empty whatToShow: " + whatToShow); System.out.println(); }
Two names are equal if they and either both are null or the name t is wild and the name p is non-null, or the two strings are equal.
Params:
  • p – part string from the node.
  • t – target string, which may be WILD.
Returns:true if the strings match according to the rules of this method.
/** * Two names are equal if they and either both are null or * the name t is wild and the name p is non-null, or the two * strings are equal. * * @param p part string from the node. * @param t target string, which may be {@link #WILD}. * * @return true if the strings match according to the rules of this method. */
private static final boolean subPartMatch(String p, String t) { // boolean b = (p == t) || ((null != p) && ((t == WILD) || p.equals(t))); // System.out.println("subPartMatch - p: "+p+", t: "+t+", result: "+b); return (p == t) || ((null != p) && ((t == WILD) || p.equals(t))); }
This is temporary to patch over Xerces issue with representing DOM namespaces as "".
Params:
  • p – part string from the node, which may represent the null namespace as null or as "".
  • t – target string, which may be WILD.
Returns:true if the strings match according to the rules of this method.
/** * This is temporary to patch over Xerces issue with representing DOM * namespaces as "". * * @param p part string from the node, which may represent the null namespace * as null or as "". * @param t target string, which may be {@link #WILD}. * * @return true if the strings match according to the rules of this method. */
private static final boolean subPartMatchNS(String p, String t) { return (p == t) || ((null != p) && ((p.length() > 0) ? ((t == WILD) || p.equals(t)) : null == t)); }
Tell what the test score is for the given node.
Params:
  • xctxt – XPath runtime context.
  • context – The node being tested.
Throws:
Returns:SCORE_NODETEST, SCORE_NONE, SCORE_NSWILD, SCORE_QNAME, or SCORE_OTHER.
/** * Tell what the test score is for the given node. * * * @param xctxt XPath runtime context. * @param context The node being tested. * * @return {@link org.apache.xpath.patterns.NodeTest#SCORE_NODETEST}, * {@link org.apache.xpath.patterns.NodeTest#SCORE_NONE}, * {@link org.apache.xpath.patterns.NodeTest#SCORE_NSWILD}, * {@link org.apache.xpath.patterns.NodeTest#SCORE_QNAME}, or * {@link org.apache.xpath.patterns.NodeTest#SCORE_OTHER}. * * @throws javax.xml.transform.TransformerException */
public XObject execute(XPathContext xctxt, int context) throws javax.xml.transform.TransformerException { DTM dtm = xctxt.getDTM(context); short nodeType = dtm.getNodeType(context); if (m_whatToShow == DTMFilter.SHOW_ALL) return m_score; int nodeBit = (m_whatToShow & (0x00000001 << (nodeType - 1))); switch (nodeBit) { case DTMFilter.SHOW_DOCUMENT_FRAGMENT : case DTMFilter.SHOW_DOCUMENT : return SCORE_OTHER; case DTMFilter.SHOW_COMMENT : return m_score; case DTMFilter.SHOW_CDATA_SECTION : case DTMFilter.SHOW_TEXT : // was: // return (!xctxt.getDOMHelper().shouldStripSourceNode(context)) // ? m_score : SCORE_NONE; return m_score; case DTMFilter.SHOW_PROCESSING_INSTRUCTION : return subPartMatch(dtm.getNodeName(context), m_name) ? m_score : SCORE_NONE; // From the draft: "Two expanded names are equal if they // have the same local part, and either both have no URI or // both have the same URI." // "A node test * is true for any node of the principal node type. // For example, child::* will select all element children of the // context node, and attribute::* will select all attributes of // the context node." // "A node test can have the form NCName:*. In this case, the prefix // is expanded in the same way as with a QName using the context // namespace declarations. The node test will be true for any node // of the principal type whose expanded name has the URI to which // the prefix expands, regardless of the local part of the name." case DTMFilter.SHOW_NAMESPACE : { String ns = dtm.getLocalName(context); return (subPartMatch(ns, m_name)) ? m_score : SCORE_NONE; } case DTMFilter.SHOW_ATTRIBUTE : case DTMFilter.SHOW_ELEMENT : { return (m_isTotallyWild || (subPartMatchNS(dtm.getNamespaceURI(context), m_namespace) && subPartMatch(dtm.getLocalName(context), m_name))) ? m_score : SCORE_NONE; } default : return SCORE_NONE; } // end switch(testType) }
Tell what the test score is for the given node.
Params:
  • xctxt – XPath runtime context.
  • context – The node being tested.
Throws:
Returns:SCORE_NODETEST, SCORE_NONE, SCORE_NSWILD, SCORE_QNAME, or SCORE_OTHER.
/** * Tell what the test score is for the given node. * * * @param xctxt XPath runtime context. * @param context The node being tested. * * @return {@link org.apache.xpath.patterns.NodeTest#SCORE_NODETEST}, * {@link org.apache.xpath.patterns.NodeTest#SCORE_NONE}, * {@link org.apache.xpath.patterns.NodeTest#SCORE_NSWILD}, * {@link org.apache.xpath.patterns.NodeTest#SCORE_QNAME}, or * {@link org.apache.xpath.patterns.NodeTest#SCORE_OTHER}. * * @throws javax.xml.transform.TransformerException */
public XObject execute(XPathContext xctxt, int context, DTM dtm, int expType) throws javax.xml.transform.TransformerException { if (m_whatToShow == DTMFilter.SHOW_ALL) return m_score; int nodeBit = (m_whatToShow & (0x00000001 << ((dtm.getNodeType(context)) - 1))); switch (nodeBit) { case DTMFilter.SHOW_DOCUMENT_FRAGMENT : case DTMFilter.SHOW_DOCUMENT : return SCORE_OTHER; case DTMFilter.SHOW_COMMENT : return m_score; case DTMFilter.SHOW_CDATA_SECTION : case DTMFilter.SHOW_TEXT : // was: // return (!xctxt.getDOMHelper().shouldStripSourceNode(context)) // ? m_score : SCORE_NONE; return m_score; case DTMFilter.SHOW_PROCESSING_INSTRUCTION : return subPartMatch(dtm.getNodeName(context), m_name) ? m_score : SCORE_NONE; // From the draft: "Two expanded names are equal if they // have the same local part, and either both have no URI or // both have the same URI." // "A node test * is true for any node of the principal node type. // For example, child::* will select all element children of the // context node, and attribute::* will select all attributes of // the context node." // "A node test can have the form NCName:*. In this case, the prefix // is expanded in the same way as with a QName using the context // namespace declarations. The node test will be true for any node // of the principal type whose expanded name has the URI to which // the prefix expands, regardless of the local part of the name." case DTMFilter.SHOW_NAMESPACE : { String ns = dtm.getLocalName(context); return (subPartMatch(ns, m_name)) ? m_score : SCORE_NONE; } case DTMFilter.SHOW_ATTRIBUTE : case DTMFilter.SHOW_ELEMENT : { return (m_isTotallyWild || (subPartMatchNS(dtm.getNamespaceURI(context), m_namespace) && subPartMatch(dtm.getLocalName(context), m_name))) ? m_score : SCORE_NONE; } default : return SCORE_NONE; } // end switch(testType) }
Test the current node to see if it matches the given node test.
Params:
  • xctxt – XPath runtime context.
Throws:
Returns:SCORE_NODETEST, SCORE_NONE, SCORE_NSWILD, SCORE_QNAME, or SCORE_OTHER.
/** * Test the current node to see if it matches the given node test. * * @param xctxt XPath runtime context. * * @return {@link org.apache.xpath.patterns.NodeTest#SCORE_NODETEST}, * {@link org.apache.xpath.patterns.NodeTest#SCORE_NONE}, * {@link org.apache.xpath.patterns.NodeTest#SCORE_NSWILD}, * {@link org.apache.xpath.patterns.NodeTest#SCORE_QNAME}, or * {@link org.apache.xpath.patterns.NodeTest#SCORE_OTHER}. * * @throws javax.xml.transform.TransformerException */
public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException { return execute(xctxt, xctxt.getCurrentNode()); }
Node tests by themselves do not need to fix up variables.
/** * Node tests by themselves do not need to fix up variables. */
public void fixupVariables(java.util.Vector vars, int globalsSize) { // no-op }
See Also:
  • callVisitors.callVisitors(ExpressionOwner, XPathVisitor)
/** * @see org.apache.xpath.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor) */
public void callVisitors(ExpressionOwner owner, XPathVisitor visitor) { assertion(false, "callVisitors should not be called for this object!!!"); } }