• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 /*
19  * $Id$
20  */
21 
22 package org.apache.qetest.xalanj2;
23 import java.io.PrintWriter;
24 import java.io.StringWriter;
25 import java.lang.reflect.Method;
26 import java.util.Properties;
27 
28 import javax.xml.transform.Transformer;
29 
30 import org.apache.xalan.templates.ElemLiteralResult;
31 import org.apache.xalan.templates.ElemTemplate;
32 import org.apache.xalan.templates.ElemTemplateElement;
33 import org.apache.xalan.templates.ElemTextLiteral;
34 import org.apache.xalan.transformer.TransformerImpl;
35 import org.apache.xml.dtm.ref.DTMNodeProxy;
36 import org.apache.xpath.XPath;
37 import org.w3c.dom.Attr;
38 import org.w3c.dom.Element;
39 import org.w3c.dom.Node;
40 import org.w3c.dom.NodeList;
41 
42 /**
43  * Static utility for dumping info about common Xalan objects.
44  * Cheap-o string representations of some common properties
45  * of various objects; supports some formatting and encapsulation
46  * but could use improvements.
47  * Note: currently purposefully outputs plain strings, not
48  * any XML-like elements, so it's easier for other XML-like
49  * logging utilities to output our data without escaping, etc.
50  *
51  * @author shane_curcuru@lotus.com
52  * @version $Id$
53  */
54 public abstract class XalanDumper
55 {
56     // abstract class cannot be instantiated
57 
58     /** Simple text constants: for items that are null.  */
59     public static final String NULL = "NULL";
60     /** Simple text constants: separator between items.  */
61     public static final String SEP = ";";
62     /** Simple text constants: beginning a block of items.  */
63     public static final String LBRACKET = "[";
64     /** Simple text constants: ending a block of items.  */
65     public static final String RBRACKET = "]";
66     /** Simple text constants: line number.  */
67     public static final String LNUM = "L";
68     /** Simple text constants: column number.  */
69     public static final String CNUM = "C";
70 
71     /** Simple output formats: default behavior.  */
72     public static final int DUMP_DEFAULT = 0;
73     /** Simple output formats: verbose: extra output.  */
74     public static final int DUMP_VERBOSE = 1;
75     /** Simple output formats: a contained object.  */
76     public static final int DUMP_CONTAINED = 2;
77     /** Simple output formats: don't close block.  */
78     public static final int DUMP_NOCLOSE = 4;
79     /** Simple output formats: don't include id's or other items likely to change.  */
80     public static final int DUMP_NOIDS = 8;
81 
82     /** Cheap-o recursion marker: already recursing in Nodes/NodeLists.  */
83     public static final int DUMP_NODE_RECURSION = 16;
84 
85     /**
86      * Return String describing an ElemTemplateElement.
87      *
88      * @param elem the ElemTemplateElement to print info of
89      * @param dumpLevel what format/how much to dump
90      */
dump(ElemTemplateElement elem, int dumpLevel)91     public static String dump(ElemTemplateElement elem, int dumpLevel)
92     {
93         StringBuffer buf = new StringBuffer("ElemTemplateElement" + LBRACKET);
94         if (null == elem)
95             return buf.toString() + NULL + RBRACKET;
96 
97         // Note for user if it's an LRE or an xsl element
98         if(elem instanceof ElemLiteralResult)
99             buf.append("LRE:");
100         else
101             buf.append("xsl:");
102 
103         buf.append(elem.getNodeName());
104         buf.append(SEP + LNUM + elem.getLineNumber());
105         buf.append(SEP + CNUM + elem.getColumnNumber());
106         buf.append(SEP + "getLength=" + elem.getLength());
107         if (DUMP_VERBOSE == (dumpLevel & DUMP_VERBOSE))
108         {
109             // Only include systemIds (which are long) if verbose
110             buf.append(SEP + "getSystemId=" + elem.getSystemId());
111             buf.append(SEP + "getStylesheet=" + elem.getStylesheet().getSystemId());
112         }
113         try
114         {
115             Class cl = ((Object)elem).getClass();
116             Method getSelect = cl.getMethod("getSelect", null);
117             if(null != getSelect)
118             {
119                 buf.append(SEP + "select=");
120                 XPath xpath = (XPath)getSelect.invoke(elem, null);
121                 buf.append(xpath.getPatternString());
122             }
123         }
124         catch(Exception e)
125         {
126             // no-op: just don't put in the select info for these items
127         }
128         if (DUMP_NOCLOSE == (dumpLevel & DUMP_NOCLOSE))
129             return buf.toString();
130         else
131             return buf.toString() + RBRACKET;
132     }
133 
134 
135     /**
136      * Return String describing an ElemTextLiteral.
137      *
138      * @param elem the ElemTextLiteral to print info of
139      * @param dumpLevel what format/how much to dump
140      */
dump(ElemTextLiteral elem, int dumpLevel)141     public static String dump(ElemTextLiteral elem, int dumpLevel)
142     {
143         StringBuffer buf = new StringBuffer("ElemTextLiteral" + LBRACKET);
144         if (null == elem)
145             return buf.toString() + NULL + RBRACKET;
146 
147         buf.append(elem.getNodeName()); // I don't think this ever changes from #Text?
148         buf.append(SEP + LNUM + elem.getLineNumber());
149         buf.append(SEP + CNUM + elem.getColumnNumber());
150 
151         String chars = new String(elem.getChars(), 0, elem.getChars().length);
152         buf.append(SEP + "chars=" + chars.trim());
153 
154         if (DUMP_NOCLOSE == (dumpLevel & DUMP_NOCLOSE))
155             return buf.toString();
156         else
157             return buf.toString() + RBRACKET;
158     }
159 
160     /**
161      * Return String describing an ElemTemplate.
162      *
163      * @param elem the ElemTemplate to print info of
164      * @param dumpLevel what format/how much to dump
165      */
dump(ElemTemplate elem, int dumpLevel)166     public static String dump(ElemTemplate elem, int dumpLevel)
167     {
168         StringBuffer buf = new StringBuffer("ElemTemplate" + LBRACKET);
169         if (null == elem)
170             return buf.toString() + NULL + RBRACKET;
171 
172         buf.append("xsl:" + elem.getNodeName());
173         buf.append(SEP + LNUM + elem.getLineNumber());
174         buf.append(SEP + CNUM + elem.getColumnNumber());
175         if (DUMP_VERBOSE == (dumpLevel & DUMP_VERBOSE))
176         {
177             // Only include systemIds (which are long) if verbose
178             buf.append(SEP + "getSystemId=" + elem.getSystemId());
179             buf.append(SEP + "getStylesheet=" + elem.getStylesheet().getSystemId());
180         }
181         try
182         {
183             Class cl = ((Object)elem).getClass();
184             Method getSelect = cl.getMethod("getSelect", null);
185             if(null != getSelect)
186             {
187                 buf.append(SEP + "select=");
188                 XPath xpath = (XPath)getSelect.invoke(elem, null);
189                 buf.append(xpath.getPatternString());
190             }
191         }
192         catch(Exception e)
193         {
194             // no-op: just don't put in the select info for these items
195         }
196         if (null != elem.getMatch())
197             buf.append(SEP + "match=" + elem.getMatch().getPatternString());
198 
199         if (null != elem.getName())
200             buf.append(SEP + "name=" + elem.getName());
201 
202         if (null != elem.getMode())
203             buf.append(SEP + "mode=" + elem.getMode());
204 
205         buf.append(SEP + "priority=" + elem.getPriority());
206 
207         if (DUMP_NOCLOSE == (dumpLevel & DUMP_NOCLOSE))
208             return buf.toString();
209         else
210             return buf.toString() + RBRACKET;
211     }
212 
213 
214     /**
215      * Return String describing a Transformer.
216      * Currently just returns info about a get selected public
217      * getter methods from a Transformer.
218      * Only really useful when it can do instanceof TransformerImpl
219      * to return custom info about Xalan
220      *
221      * @param t the Transformer to print info of
222      * @param dumpLevel what format/how much to dump
223      */
dump(Transformer trans, int dumpLevel)224     public static String dump(Transformer trans, int dumpLevel)
225     {
226         if (null == trans)
227             return "Transformer" + LBRACKET + NULL + RBRACKET;
228 
229         StringBuffer buf = new StringBuffer();
230 
231         StringWriter sw = new StringWriter();
232         Properties p = trans.getOutputProperties();
233         if (null != p)
234         {
235             p.list(new PrintWriter(sw));
236             buf.append("getOutputProperties{" + sw.toString() + "}");
237         }
238 
239         if (trans instanceof TransformerImpl)
240         {
241             final TransformerImpl timpl = (TransformerImpl)trans;
242             // We have a Xalan-J 2.x basic transformer
243 
244             // Android-changed: TransformerImpl in 2.7.1 doesn't have getBaseURLOfSource() method.
245             // buf.append("getBaseURLOfSource=" + timpl.getBaseURLOfSource() + SEP);
246             // Result getOutputTarget()
247             // ContentHandler getInputContentHandler(boolean doDocFrag)
248             // DeclHandler getInputDeclHandler()
249             // LexicalHandler getInputLexicalHandler()
250             // OutputProperties getOutputFormat()
251             // Serializer getSerializer()
252             // ElemTemplateElement getCurrentElement()
253             // int getCurrentNode()
254             // ElemTemplate getCurrentTemplate()
255             // ElemTemplate getMatchedTemplate()
256             // int getMatchedNode()
257             // DTMIterator getContextNodeList()
258             // StylesheetRoot getStylesheet()
259             // int getRecursionLimit()
260             buf.append("getMode=" + timpl.getMode() + SEP);
261         }
262 
263         return "Transformer" + LBRACKET
264             + buf.toString() + RBRACKET;
265     }
266 
267 
268     /**
269      * Return String describing a Node.
270      * Currently just returns TracerEvent.printNode(n)
271      *
272      * @param n the Node to print info of
273      * @param dumpLevel what format/how much to dump
274      */
dump(Node n, int dumpLevel)275     public static String dump(Node n, int dumpLevel)
276     {
277         if (null == n)
278             return "Node" + LBRACKET + NULL + RBRACKET;
279 
280         // Copied but modified from TracerEvent; ditch hashCode
281         StringBuffer buf = new StringBuffer();
282 
283         if (n instanceof Element)
284         {
285             buf.append(n.getNodeName());
286 
287             Node c = n.getFirstChild();
288 
289             while (null != c)
290             {
291                 if (c instanceof Attr)
292                 {
293                     buf.append(dump(c, dumpLevel | DUMP_NODE_RECURSION) + " ");
294                 }
295                 c = c.getNextSibling();
296             }
297         }
298         else
299         {
300             if (n instanceof Attr)
301             {
302                 buf.append(n.getNodeName() + "=" + n.getNodeValue());
303             }
304             else
305             {
306                 buf.append(n.getNodeName());
307             }
308         }
309 
310 
311         // If we're already recursing, don't bother printing out 'Node' again
312         if (DUMP_NODE_RECURSION == (dumpLevel & DUMP_NODE_RECURSION))
313             return LBRACKET + buf.toString() + RBRACKET;
314         else
315             return "Node" + LBRACKET + buf.toString() + RBRACKET;
316     }
317 
318     /**
319      * Return String describing a DTMNodeProxy.
320      * This is the Xalan-J 2.x internal wrapper for Nodes.
321      *
322      * @param n the DTMNodeProxy to print info of
323      * @param dumpLevel what format/how much to dump
324      */
dump(DTMNodeProxy n, int dumpLevel)325     public static String dump(DTMNodeProxy n, int dumpLevel)
326     {
327         if (null == n)
328             return "DTMNodeProxy" + LBRACKET + NULL + RBRACKET;
329 
330         // Copied but modified from TracerEvent; ditch hashCode
331         StringBuffer buf = new StringBuffer();
332 
333         if (DUMP_NOIDS != (dumpLevel & DUMP_NOIDS))
334         {
335             // Only include the DTM node number if asked
336             buf.append(n.getDTMNodeNumber());
337         }
338 
339         if (n instanceof Element)
340         {
341             buf.append(n.getNodeName());
342             // Also output first x chars of value
343             buf.append(substr(n.getNodeValue()));
344 
345             DTMNodeProxy c = (DTMNodeProxy)n.getFirstChild();
346 
347             while (null != c)
348             {
349                 buf.append(dump(c, dumpLevel | DUMP_NODE_RECURSION) + " ");
350                 c = (DTMNodeProxy)c.getNextSibling();
351             }
352         }
353         else
354         {
355             if (n instanceof Attr)
356             {
357                 buf.append(n.getNodeName() + "=" + n.getNodeValue());
358             }
359             else
360             {
361                 buf.append(n.getNodeName());
362                 // Also output first x chars of value
363                 buf.append(substr(n.getNodeValue()));
364             }
365         }
366 
367 
368         // If we're already recursing, don't bother printing out 'Node' again
369         if (DUMP_NODE_RECURSION == (dumpLevel & DUMP_NODE_RECURSION))
370             return LBRACKET + buf.toString() + RBRACKET;
371         else
372             return "DTMNodeProxy" + LBRACKET + buf.toString() + RBRACKET;
373     }
374 
375     /** Cheap-o worker method to substring a string.  */
376     public static int MAX_SUBSTR = 8;
377 
378     /** Cheap-o worker method to substring a string.  */
379     public static String SUBSTR_PREFIX = ":";
380 
381     /** Cheap-o worker method to substring a string.  */
substr(String s)382     protected static String substr(String s)
383     {
384         if (null == s)
385             return "";
386         return SUBSTR_PREFIX + s.substring(0, Math.min(s.length(), MAX_SUBSTR));
387     }
388 
389     /**
390      * Return String describing a NodeList.
391      * Currently just returns TracerEvent.printNode(n)
392      *
393      * @param nl the NodeList to print info of
394      * @param dumpLevel what format/how much to dump
395      */
dump(NodeList nl, int dumpLevel)396     public static String dump(NodeList nl, int dumpLevel)
397     {
398         if (null == nl)
399             return "NodeList" + LBRACKET + NULL + RBRACKET;
400 
401         StringBuffer buf = new StringBuffer();
402 
403         int len = nl.getLength() - 1;
404         int i = 0;
405         while (i < len)
406         {
407             Node n = nl.item(i);
408             if (null != n)
409             {
410                 buf.append(dump(n, dumpLevel) + ", ");
411             }
412             ++i;
413         }
414 
415         if (i == len)
416         {
417             Node n = nl.item(len);
418             if (null != n)
419             {
420                 buf.append(dump(n, dumpLevel));
421             }
422         }
423         return "NodeList" + LBRACKET
424             + buf.toString() + RBRACKET;
425     }
426 
427 
428     /**
429      * Print String type of node.
430      * @param n Node to report type of
431      * @return String type name
432      */
dumpNodeType(Node n)433     public static String dumpNodeType(Node n)
434     {
435         if (null == n)
436             return NULL;
437         switch (n.getNodeType())
438         {
439         case Node.DOCUMENT_NODE :
440             return "DOCUMENT_NODE";
441 
442         case Node.ELEMENT_NODE :
443             return "ELEMENT_NODE";
444 
445         case Node.CDATA_SECTION_NODE :
446             return "CDATA_SECTION_NODE";
447 
448         case Node.ENTITY_REFERENCE_NODE :
449             return "ENTITY_REFERENCE_NODE";
450 
451         case Node.ATTRIBUTE_NODE :
452             return "ATTRIBUTE_NODE";
453 
454         case Node.COMMENT_NODE :
455             return "COMMENT_NODE";
456 
457         case Node.ENTITY_NODE :
458             return "ENTITY_NODE";
459 
460         case Node.NOTATION_NODE :
461             return "NOTATION_NODE";
462 
463         case Node.PROCESSING_INSTRUCTION_NODE :
464             return "PROCESSING_INSTRUCTION_NODE";
465 
466         case Node.TEXT_NODE :
467             return "TEXT_NODE";
468 
469         default :
470             return "UNKNOWN_NODE";
471         }
472     }  // end of dumpNodeType()
473 
474 }
475