001: /*
002: * Copyright (c) 2000-2001 Sosnoski Software Solutions, Inc.
003: *
004: * Permission is hereby granted, free of charge, to any person obtaining a copy
005: * of this software and associated documentation files (the "Software"), to deal
006: * in the Software without restriction, including without limitation the rights
007: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008: * copies of the Software, and to permit persons to whom the Software is
009: * furnished to do so, subject to the following conditions:
010: *
011: * The above copyright notice and this permission notice shall be included in
012: * all copies or substantial portions of the Software.
013: *
014: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
019: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
020: * IN THE SOFTWARE.
021: */
022:
023: package com.sosnoski.xmlbench;
024:
025: import java.io.*;
026: import java.util.*;
027:
028: import org.gjt.xpp.*;
029:
030: /**
031: * Abstract base class for benchmarks measuring performance of the XPP
032: * document representation. This base class implementation can be customized
033: * by subclasses to experiment with options for the representation, in
034: * particular for trying the pull node feature.<p>
035: *
036: * This code is based on a sample provided by Aleksander Slominski.
037: *
038: * @author Dennis M. Sosnoski
039: * @version 1.2
040: */
041:
042: public abstract class BenchXPP extends BenchDocBase {
043: /** Pull parser factory used within a test run. */
044: protected XmlPullParserFactory m_parserFactory;
045:
046: /** XML recorder used within a test run. */
047: protected XmlRecorder m_recorder;
048:
049: /**
050: * Constructor.
051: *
052: * @param config test configuration name
053: */
054:
055: protected BenchXPP(String config) {
056: super (config);
057: }
058:
059: /**
060: * Walk subtree for element. This recursively walks through the document
061: * nodes under an element, accumulating summary information.
062: *
063: * @param element element to be walked
064: * @param summary document summary information
065: */
066:
067: protected void walkElement(XmlNode element, DocumentSummary summary) {
068:
069: // include attribute values in summary
070: int acnt = element.getAttributeCount();
071: for (int i = 0; i < acnt; i++) {
072: summary.addAttribute(element.getAttributeValue(i).length());
073: }
074:
075: // loop through children
076: int ccnt = element.getChildrenCount();
077: for (int i = 0; i < ccnt; i++) {
078:
079: // handle child by type
080: Object child = element.getChildAt(i);
081: if (child instanceof String) {
082: summary.addContent(child.toString().length());
083: } else if (child instanceof XmlNode) {
084: summary.addElements(1);
085: walkElement((XmlNode) child, summary);
086: }
087:
088: }
089: }
090:
091: /**
092: * Walk and summarize document. This method walks through the nodes
093: * of the document, accumulating summary information.
094: *
095: * @param doc document representation to be walked
096: * @param summary output document summary information
097: */
098:
099: protected void walk(Object doc, DocumentSummary summary) {
100: summary.addElements(1);
101: walkElement((XmlNode) doc, summary);
102: }
103:
104: /**
105: * Output a document as XML text. This implementation uses the method
106: * defined by XPP to output a text representation of the document.
107: *
108: * @param doc document representation to be output
109: * @param out XML document output stream
110: */
111:
112: protected void output(Object doc, OutputStream out) {
113: try {
114: if (m_recorder == null) {
115: if (m_parserFactory == null) {
116: m_parserFactory = XmlPullParserFactory
117: .newInstance();
118: m_parserFactory.setNamespaceAware(true);
119: }
120: m_recorder = m_parserFactory.newRecorder();
121: }
122: Writer writer = new OutputStreamWriter(out);
123: m_recorder.setOutput(writer);
124: m_recorder.writeNode((XmlNode) doc);
125: writer.close();
126: } catch (Exception ex) {
127: ex.printStackTrace(System.err);
128: System.exit(0);
129: }
130: }
131:
132: /**
133: * Modify subtree for element. This recursively walks through the document
134: * nodes under an element, performing the modifications.
135: *
136: * @param element element to be walked
137: * @throws XmlPullParserException on error walking tree
138: */
139:
140: protected void modifyElement(XmlNode element)
141: throws XmlPullParserException {
142:
143: // check for children present
144: int ccnt = element.getChildrenCount();
145: if (ccnt > 0) {
146:
147: // loop through child nodes
148: String uri = null;
149: String prefix = null;
150: String raw = null;
151: boolean content = false;
152: for (int i = 0; i < ccnt; i++) {
153:
154: // handle child by node type
155: Object child = element.getChildAt(i);
156: if (child instanceof String) {
157:
158: // trim whitespace from content text
159: String trimmed = child.toString().trim();
160: if (trimmed.length() == 0) {
161:
162: // delete child if only whitespace (adjusting index)
163: element.removeChildAt(i--);
164: --ccnt;
165:
166: } else {
167:
168: // construct qualified name for wrapper element
169: if (!content) {
170: uri = element.getNamespaceUri();
171: prefix = element.getPrefix();
172: raw = (prefix == null) ? "text" : prefix
173: + ":text";
174: content = true;
175: }
176:
177: // wrap the trimmed content with new element
178: XmlNode text = m_parserFactory.newNode();
179: text.appendChild(trimmed);
180: element.replaceChildAt(i, text);
181: text.modifyTag(uri, "text", raw);
182:
183: }
184: } else if (child instanceof XmlNode) {
185:
186: // handle child elements with recursive call
187: modifyElement((XmlNode) child);
188:
189: }
190: }
191:
192: // check if we've seen any non-whitespace content for element
193: if (content) {
194:
195: // add attribute flagging content found
196: element.addAttribute(uri, "text", raw, "true");
197:
198: }
199: }
200: }
201:
202: /**
203: * Modify a document representation. This implementation of the abstract
204: * superclass method walks the document representation performing the
205: * following modifications: remove all content segments which consist only
206: * of whitespace; add an attribute "text" set to "true" to any elements
207: * which directly contain non-whitespace text content; and replace each
208: * non-whitespace text content segment with a "text" element which wraps
209: * the trimmed content.
210: *
211: * @param doc document representation to be modified
212: */
213:
214: protected void modify(Object doc) {
215: try {
216: modifyElement((XmlNode) doc);
217: } catch (XmlPullParserException ex) {
218: ex.printStackTrace(System.err);
219: System.exit(0);
220: }
221: }
222:
223: /**
224: * Reset test class instance. This discards the parser factory and recorder
225: * used within a test pass.
226: */
227:
228: protected void reset() {
229: m_parserFactory = null;
230: m_recorder = null;
231: }
232: }
|