KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xpath > patterns > NodeTest


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: NodeTest.java,v 1.27 2004/02/17 04:35:37 minchau Exp $
18  */

19 package org.apache.xpath.patterns;
20
21 import org.apache.xml.dtm.DTM;
22 import org.apache.xml.dtm.DTMFilter;
23 import org.apache.xpath.Expression;
24 import org.apache.xpath.ExpressionOwner;
25 import org.apache.xpath.XPath;
26 import org.apache.xpath.XPathContext;
27 import org.apache.xpath.XPathVisitor;
28 import org.apache.xpath.objects.XNumber;
29 import org.apache.xpath.objects.XObject;
30
31 /**
32  * This is the basic node test class for both match patterns and location path
33  * steps.
34  * @xsl.usage advanced
35  */

36 public class NodeTest extends Expression
37 {
38
39   /**
40    * The namespace or local name for node tests with a wildcard.
41    * @see <a HREF="http://www.w3.org/TR/xpath#NT-NameTest">the XPath NameTest production.</a>
42    */

43   public static final String JavaDoc WILD = "*";
44
45   /**
46    * The URL to pass to the Node#supports method, to see if the
47    * DOM has already been stripped of whitespace nodes.
48    */

49   public static final String JavaDoc SUPPORTS_PRE_STRIPPING =
50     "http://xml.apache.org/xpath/features/whitespace-pre-stripping";
51
52   /**
53    * This attribute determines which node types are accepted.
54    * @serial
55    */

56   protected int m_whatToShow;
57
58   /**
59    * Special bitmap for match patterns starting with a function.
60    * Make sure this does not conflict with {@link org.w3c.dom.traversal.NodeFilter}.
61    */

62   public static final int SHOW_BYFUNCTION = 0x00010000;
63
64   /**
65    * This attribute determines which node types are accepted.
66    * These constants are defined in the {@link org.w3c.dom.traversal.NodeFilter}
67    * interface.
68    *
69    * @return bitset mainly defined in {@link org.w3c.dom.traversal.NodeFilter}.
70    */

71   public int getWhatToShow()
72   {
73     return m_whatToShow;
74   }
75   
76   /**
77    * This attribute determines which node types are accepted.
78    * These constants are defined in the {@link org.w3c.dom.traversal.NodeFilter}
79    * interface.
80    *
81    * @param what bitset mainly defined in {@link org.w3c.dom.traversal.NodeFilter}.
82    */

83   public void setWhatToShow(int what)
84   {
85     m_whatToShow = what;
86   }
87
88   /**
89    * The namespace to be tested for, which may be null.
90    * @serial
91    */

92   String JavaDoc m_namespace;
93
94   /**
95    * Return the namespace to be tested.
96    *
97    * @return The namespace to be tested for, or {@link #WILD}, or null.
98    */

99   public String JavaDoc getNamespace()
100   {
101     return m_namespace;
102   }
103
104   /**
105    * Set the namespace to be tested.
106    *
107    * @param ns The namespace to be tested for, or {@link #WILD}, or null.
108    */

109   public void setNamespace(String JavaDoc ns)
110   {
111     m_namespace = ns;
112   }
113
114   /**
115    * The local name to be tested for.
116    * @serial
117    */

118   protected String JavaDoc m_name;
119
120   /**
121    * Return the local name to be tested.
122    *
123    * @return the local name to be tested, or {@link #WILD}, or an empty string.
124    */

125   public String JavaDoc getLocalName()
126   {
127     return (null == m_name) ? "" : m_name;
128   }
129
130   /**
131    * Set the local name to be tested.
132    *
133    * @param name the local name to be tested, or {@link #WILD}, or an empty string.
134    */

135   public void setLocalName(String JavaDoc name)
136   {
137     m_name = name;
138   }
139
140   /**
141    * Statically calculated score for this test. One of
142    * {@link #SCORE_NODETEST},
143    * {@link #SCORE_NONE},
144    * {@link #SCORE_NSWILD},
145    * {@link #SCORE_QNAME}, or
146    * {@link #SCORE_OTHER}.
147    * @serial
148    */

149   XNumber m_score;
150
151   /**
152    * The match score if the pattern consists of just a NodeTest.
153    * @see <a HREF="http://www.w3.org/TR/xslt#conflict">XSLT Specification - 5.5 Conflict Resolution for Template Rules</a>
154    */

155   public static final XNumber SCORE_NODETEST =
156     new XNumber(XPath.MATCH_SCORE_NODETEST);
157
158   /**
159    * The match score if the pattern pattern has the form NCName:*.
160    * @see <a HREF="http://www.w3.org/TR/xslt#conflict">XSLT Specification - 5.5 Conflict Resolution for Template Rules</a>
161    */

162   public static final XNumber SCORE_NSWILD =
163     new XNumber(XPath.MATCH_SCORE_NSWILD);
164
165   /**
166    * The match score if the pattern has the form
167    * of a QName optionally preceded by an @ character.
168    * @see <a HREF="http://www.w3.org/TR/xslt#conflict">XSLT Specification - 5.5 Conflict Resolution for Template Rules</a>
169    */

170   public static final XNumber SCORE_QNAME =
171     new XNumber(XPath.MATCH_SCORE_QNAME);
172
173   /**
174    * The match score if the pattern consists of something
175    * other than just a NodeTest or just a qname.
176    * @see <a HREF="http://www.w3.org/TR/xslt#conflict">XSLT Specification - 5.5 Conflict Resolution for Template Rules</a>
177    */

178   public static final XNumber SCORE_OTHER =
179     new XNumber(XPath.MATCH_SCORE_OTHER);
180
181   /**
182    * The match score if no match is made.
183    * @see <a HREF="http://www.w3.org/TR/xslt#conflict">XSLT Specification - 5.5 Conflict Resolution for Template Rules</a>
184    */

185   public static final XNumber SCORE_NONE =
186     new XNumber(XPath.MATCH_SCORE_NONE);
187
188   /**
189    * Construct an NodeTest that tests for namespaces and node names.
190    *
191    *
192    * @param whatToShow Bit set defined mainly by {@link org.w3c.dom.traversal.NodeFilter}.
193    * @param namespace The namespace to be tested.
194    * @param name The local name to be tested.
195    */

196   public NodeTest(int whatToShow, String JavaDoc namespace, String JavaDoc name)
197   {
198     initNodeTest(whatToShow, namespace, name);
199   }
200
201   /**
202    * Construct an NodeTest that doesn't test for node names.
203    *
204    *
205    * @param whatToShow Bit set defined mainly by {@link org.w3c.dom.traversal.NodeFilter}.
206    */

207   public NodeTest(int whatToShow)
208   {
209     initNodeTest(whatToShow);
210   }
211   
212   /**
213    * @see Expression#deepEquals(Expression)
214    */

215   public boolean deepEquals(Expression expr)
216   {
217     if(!isSameClass(expr))
218         return false;
219         
220     NodeTest nt = (NodeTest)expr;
221
222     if(null != nt.m_name)
223     {
224         if(null == m_name)
225             return false;
226         else if(!nt.m_name.equals(m_name))
227             return false;
228     }
229     else if(null != m_name)
230         return false;
231
232     if(null != nt.m_namespace)
233     {
234         if(null == m_namespace)
235             return false;
236         else if(!nt.m_namespace.equals(m_namespace))
237             return false;
238     }
239     else if(null != m_namespace)
240         return false;
241                 
242     if(m_whatToShow != nt.m_whatToShow)
243         return false;
244         
245     if(m_isTotallyWild != nt.m_isTotallyWild)
246         return false;
247
248     return true;
249   }
250
251   /**
252    * Null argument constructor.
253    */

254   public NodeTest(){}
255
256   /**
257    * Initialize this node test by setting the whatToShow property, and
258    * calculating the score that this test will return if a test succeeds.
259    *
260    *
261    * @param whatToShow Bit set defined mainly by {@link org.w3c.dom.traversal.NodeFilter}.
262    */

263   public void initNodeTest(int whatToShow)
264   {
265
266     m_whatToShow = whatToShow;
267
268     calcScore();
269   }
270
271   /**
272    * Initialize this node test by setting the whatToShow property and the
273    * namespace and local name, and
274    * calculating the score that this test will return if a test succeeds.
275    *
276    *
277    * @param whatToShow Bit set defined mainly by {@link org.w3c.dom.traversal.NodeFilter}.
278    * @param namespace The namespace to be tested.
279    * @param name The local name to be tested.
280    */

281   public void initNodeTest(int whatToShow, String JavaDoc namespace, String JavaDoc name)
282   {
283
284     m_whatToShow = whatToShow;
285     m_namespace = namespace;
286     m_name = name;
287
288     calcScore();
289   }
290
291   /**
292    * True if this test has a null namespace and a local name of {@link #WILD}.
293    * @serial
294    */

295   private boolean m_isTotallyWild;
296   
297   /**
298    * Get the static score for this node test.
299    * @return Should be one of the SCORE_XXX constants.
300    */

301   public XNumber getStaticScore()
302   {
303     return m_score;
304   }
305   
306   /**
307    * Set the static score for this node test.
308    * @param score Should be one of the SCORE_XXX constants.
309    */

310   public void setStaticScore(XNumber score)
311   {
312     m_score = score;
313   }
314
315   /**
316    * Static calc of match score.
317    */

318   protected void calcScore()
319   {
320
321     if ((m_namespace == null) && (m_name == null))
322       m_score = SCORE_NODETEST;
323     else if (((m_namespace == WILD) || (m_namespace == null))
324              && (m_name == WILD))
325       m_score = SCORE_NODETEST;
326     else if ((m_namespace != WILD) && (m_name == WILD))
327       m_score = SCORE_NSWILD;
328     else
329       m_score = SCORE_QNAME;
330
331     m_isTotallyWild = (m_namespace == null && m_name == WILD);
332   }
333
334   /**
335    * Get the score that this test will return if a test succeeds.
336    *
337    *
338    * @return the score that this test will return if a test succeeds.
339    */

340   public double getDefaultScore()
341   {
342     return m_score.num();
343   }
344   
345   /**
346    * Tell what node type to test, if not DTMFilter.SHOW_ALL.
347    *
348    * @param whatToShow Bit set defined mainly by
349    * {@link org.apache.xml.dtm.DTMFilter}.
350    * @return the node type for the whatToShow. Since whatToShow can specify
351    * multiple types, it will return the first bit tested that is on,
352    * so the caller of this function should take care that this is
353    * the function they really want to call. If none of the known bits
354    * are set, this function will return zero.
355    */

356   public static int getNodeTypeTest(int whatToShow)
357   {
358     // %REVIEW% Is there a better way?
359
if (0 != (whatToShow & DTMFilter.SHOW_ELEMENT))
360       return DTM.ELEMENT_NODE;
361
362     if (0 != (whatToShow & DTMFilter.SHOW_ATTRIBUTE))
363       return DTM.ATTRIBUTE_NODE;
364       
365     if (0 != (whatToShow & DTMFilter.SHOW_TEXT))
366       return DTM.TEXT_NODE;
367       
368     if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT))
369       return DTM.DOCUMENT_NODE;
370
371     if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT_FRAGMENT))
372       return DTM.DOCUMENT_FRAGMENT_NODE;
373
374     if (0 != (whatToShow & DTMFilter.SHOW_NAMESPACE))
375       return DTM.NAMESPACE_NODE;
376
377     if (0 != (whatToShow & DTMFilter.SHOW_COMMENT))
378       return DTM.COMMENT_NODE;
379
380     if (0 != (whatToShow & DTMFilter.SHOW_PROCESSING_INSTRUCTION))
381       return DTM.PROCESSING_INSTRUCTION_NODE;
382
383     if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT_TYPE))
384       return DTM.DOCUMENT_TYPE_NODE;
385
386     if (0 != (whatToShow & DTMFilter.SHOW_ENTITY))
387       return DTM.ENTITY_NODE;
388
389     if (0 != (whatToShow & DTMFilter.SHOW_ENTITY_REFERENCE))
390       return DTM.ENTITY_REFERENCE_NODE;
391
392     if (0 != (whatToShow & DTMFilter.SHOW_NOTATION))
393       return DTM.NOTATION_NODE;
394       
395     if (0 != (whatToShow & DTMFilter.SHOW_CDATA_SECTION))
396       return DTM.CDATA_SECTION_NODE;
397
398
399     return 0;
400   }
401
402
403   /**
404    * Do a diagnostics dump of a whatToShow bit set.
405    *
406    *
407    * @param whatToShow Bit set defined mainly by
408    * {@link org.apache.xml.dtm.DTMFilter}.
409    */

410   public static void debugWhatToShow(int whatToShow)
411   {
412
413     java.util.Vector JavaDoc v = new java.util.Vector JavaDoc();
414
415     if (0 != (whatToShow & DTMFilter.SHOW_ATTRIBUTE))
416       v.addElement("SHOW_ATTRIBUTE");
417       
418     if (0 != (whatToShow & DTMFilter.SHOW_NAMESPACE))
419       v.addElement("SHOW_NAMESPACE");
420
421     if (0 != (whatToShow & DTMFilter.SHOW_CDATA_SECTION))
422       v.addElement("SHOW_CDATA_SECTION");
423
424     if (0 != (whatToShow & DTMFilter.SHOW_COMMENT))
425       v.addElement("SHOW_COMMENT");
426
427     if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT))
428       v.addElement("SHOW_DOCUMENT");
429
430     if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT_FRAGMENT))
431       v.addElement("SHOW_DOCUMENT_FRAGMENT");
432
433     if (0 != (whatToShow & DTMFilter.SHOW_DOCUMENT_TYPE))
434       v.addElement("SHOW_DOCUMENT_TYPE");
435
436     if (0 != (whatToShow & DTMFilter.SHOW_ELEMENT))
437       v.addElement("SHOW_ELEMENT");
438
439     if (0 != (whatToShow & DTMFilter.SHOW_ENTITY))
440       v.addElement("SHOW_ENTITY");
441
442     if (0 != (whatToShow & DTMFilter.SHOW_ENTITY_REFERENCE))
443       v.addElement("SHOW_ENTITY_REFERENCE");
444
445     if (0 != (whatToShow & DTMFilter.SHOW_NOTATION))
446       v.addElement("SHOW_NOTATION");
447
448     if (0 != (whatToShow & DTMFilter.SHOW_PROCESSING_INSTRUCTION))
449       v.addElement("SHOW_PROCESSING_INSTRUCTION");
450
451     if (0 != (whatToShow & DTMFilter.SHOW_TEXT))
452       v.addElement("SHOW_TEXT");
453
454     int n = v.size();
455
456     for (int i = 0; i < n; i++)
457     {
458       if (i > 0)
459         System.out.print(" | ");
460
461       System.out.print(v.elementAt(i));
462     }
463
464     if (0 == n)
465       System.out.print("empty whatToShow: " + whatToShow);
466
467     System.out.println();
468   }
469
470   /**
471    * Two names are equal if they and either both are null or
472    * the name t is wild and the name p is non-null, or the two
473    * strings are equal.
474    *
475    * @param p part string from the node.
476    * @param t target string, which may be {@link #WILD}.
477    *
478    * @return true if the strings match according to the rules of this method.
479    */

480   private static final boolean subPartMatch(String JavaDoc p, String JavaDoc t)
481   {
482
483     // boolean b = (p == t) || ((null != p) && ((t == WILD) || p.equals(t)));
484
// System.out.println("subPartMatch - p: "+p+", t: "+t+", result: "+b);
485
return (p == t) || ((null != p) && ((t == WILD) || p.equals(t)));
486   }
487
488   /**
489    * This is temporary to patch over Xerces issue with representing DOM
490    * namespaces as "".
491    *
492    * @param p part string from the node, which may represent the null namespace
493    * as null or as "".
494    * @param t target string, which may be {@link #WILD}.
495    *
496    * @return true if the strings match according to the rules of this method.
497    */

498   private static final boolean subPartMatchNS(String JavaDoc p, String JavaDoc t)
499   {
500
501     return (p == t)
502            || ((null != p)
503                && ((p.length() > 0)
504                    ? ((t == WILD) || p.equals(t)) : null == t));
505   }
506
507   /**
508    * Tell what the test score is for the given node.
509    *
510    *
511    * @param xctxt XPath runtime context.
512    * @param context The node being tested.
513    *
514    * @return {@link org.apache.xpath.patterns.NodeTest#SCORE_NODETEST},
515    * {@link org.apache.xpath.patterns.NodeTest#SCORE_NONE},
516    * {@link org.apache.xpath.patterns.NodeTest#SCORE_NSWILD},
517    * {@link org.apache.xpath.patterns.NodeTest#SCORE_QNAME}, or
518    * {@link org.apache.xpath.patterns.NodeTest#SCORE_OTHER}.
519    *
520    * @throws javax.xml.transform.TransformerException
521    */

522   public XObject execute(XPathContext xctxt, int context)
523           throws javax.xml.transform.TransformerException JavaDoc
524   {
525
526     DTM dtm = xctxt.getDTM(context);
527     short nodeType = dtm.getNodeType(context);
528
529     if (m_whatToShow == DTMFilter.SHOW_ALL)
530       return m_score;
531
532     int nodeBit = (m_whatToShow & (0x00000001 << (nodeType - 1)));
533
534     switch (nodeBit)
535     {
536     case DTMFilter.SHOW_DOCUMENT_FRAGMENT :
537     case DTMFilter.SHOW_DOCUMENT :
538       return SCORE_OTHER;
539     case DTMFilter.SHOW_COMMENT :
540       return m_score;
541     case DTMFilter.SHOW_CDATA_SECTION :
542     case DTMFilter.SHOW_TEXT :
543
544       // was:
545
// return (!xctxt.getDOMHelper().shouldStripSourceNode(context))
546
// ? m_score : SCORE_NONE;
547
return m_score;
548     case DTMFilter.SHOW_PROCESSING_INSTRUCTION :
549       return subPartMatch(dtm.getNodeName(context), m_name)
550              ? m_score : SCORE_NONE;
551
552     // From the draft: "Two expanded names are equal if they
553
// have the same local part, and either both have no URI or
554
// both have the same URI."
555
// "A node test * is true for any node of the principal node type.
556
// For example, child::* will select all element children of the
557
// context node, and attribute::* will select all attributes of
558
// the context node."
559
// "A node test can have the form NCName:*. In this case, the prefix
560
// is expanded in the same way as with a QName using the context
561
// namespace declarations. The node test will be true for any node
562
// of the principal type whose expanded name has the URI to which
563
// the prefix expands, regardless of the local part of the name."
564
case DTMFilter.SHOW_NAMESPACE :
565     {
566       String JavaDoc ns = dtm.getNodeValue(context);
567
568       return (subPartMatch(ns, m_name)) ? m_score : SCORE_NONE;
569     }
570     case DTMFilter.SHOW_ATTRIBUTE :
571     case DTMFilter.SHOW_ELEMENT :
572     {
573       return (m_isTotallyWild || (subPartMatchNS(dtm.getNamespaceURI(context), m_namespace) && subPartMatch(dtm.getLocalName(context), m_name)))
574              ? m_score : SCORE_NONE;
575     }
576     default :
577       return SCORE_NONE;
578     } // end switch(testType)
579
}
580   
581   /**
582    * Tell what the test score is for the given node.
583    *
584    *
585    * @param xctxt XPath runtime context.
586    * @param context The node being tested.
587    *
588    * @return {@link org.apache.xpath.patterns.NodeTest#SCORE_NODETEST},
589    * {@link org.apache.xpath.patterns.NodeTest#SCORE_NONE},
590    * {@link org.apache.xpath.patterns.NodeTest#SCORE_NSWILD},
591    * {@link org.apache.xpath.patterns.NodeTest#SCORE_QNAME}, or
592    * {@link org.apache.xpath.patterns.NodeTest#SCORE_OTHER}.
593    *
594    * @throws javax.xml.transform.TransformerException
595    */

596   public XObject execute(XPathContext xctxt, int context,
597                          DTM dtm, int expType)
598           throws javax.xml.transform.TransformerException JavaDoc
599   {
600
601     if (m_whatToShow == DTMFilter.SHOW_ALL)
602       return m_score;
603
604     int nodeBit = (m_whatToShow & (0x00000001
605                    << ((dtm.getNodeType(context)) - 1)));
606
607     switch (nodeBit)
608     {
609     case DTMFilter.SHOW_DOCUMENT_FRAGMENT :
610     case DTMFilter.SHOW_DOCUMENT :
611       return SCORE_OTHER;
612     case DTMFilter.SHOW_COMMENT :
613       return m_score;
614     case DTMFilter.SHOW_CDATA_SECTION :
615     case DTMFilter.SHOW_TEXT :
616
617       // was:
618
// return (!xctxt.getDOMHelper().shouldStripSourceNode(context))
619
// ? m_score : SCORE_NONE;
620
return m_score;
621     case DTMFilter.SHOW_PROCESSING_INSTRUCTION :
622       return subPartMatch(dtm.getNodeName(context), m_name)
623              ? m_score : SCORE_NONE;
624
625     // From the draft: "Two expanded names are equal if they
626
// have the same local part, and either both have no URI or
627
// both have the same URI."
628
// "A node test * is true for any node of the principal node type.
629
// For example, child::* will select all element children of the
630
// context node, and attribute::* will select all attributes of
631
// the context node."
632
// "A node test can have the form NCName:*. In this case, the prefix
633
// is expanded in the same way as with a QName using the context
634
// namespace declarations. The node test will be true for any node
635
// of the principal type whose expanded name has the URI to which
636
// the prefix expands, regardless of the local part of the name."
637
case DTMFilter.SHOW_NAMESPACE :
638     {
639       String JavaDoc ns = dtm.getNodeValue(context);
640
641       return (subPartMatch(ns, m_name)) ? m_score : SCORE_NONE;
642     }
643     case DTMFilter.SHOW_ATTRIBUTE :
644     case DTMFilter.SHOW_ELEMENT :
645     {
646       return (m_isTotallyWild || (subPartMatchNS(dtm.getNamespaceURI(context), m_namespace) && subPartMatch(dtm.getLocalName(context), m_name)))
647              ? m_score : SCORE_NONE;
648     }
649     default :
650       return SCORE_NONE;
651     } // end switch(testType)
652
}
653
654   /**
655    * Test the current node to see if it matches the given node test.
656    *
657    * @param xctxt XPath runtime context.
658    *
659    * @return {@link org.apache.xpath.patterns.NodeTest#SCORE_NODETEST},
660    * {@link org.apache.xpath.patterns.NodeTest#SCORE_NONE},
661    * {@link org.apache.xpath.patterns.NodeTest#SCORE_NSWILD},
662    * {@link org.apache.xpath.patterns.NodeTest#SCORE_QNAME}, or
663    * {@link org.apache.xpath.patterns.NodeTest#SCORE_OTHER}.
664    *
665    * @throws javax.xml.transform.TransformerException
666    */

667   public XObject execute(XPathContext xctxt)
668           throws javax.xml.transform.TransformerException JavaDoc
669   {
670     return execute(xctxt, xctxt.getCurrentNode());
671   }
672   
673   /**
674    * Node tests by themselves do not need to fix up variables.
675    */

676   public void fixupVariables(java.util.Vector JavaDoc vars, int globalsSize)
677   {
678     // no-op
679
}
680
681   /**
682    * @see XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
683    */

684   public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
685   {
686     assertion(false, "callVisitors should not be called for this object!!!");
687   }
688
689 }
690
Popular Tags