001: /* *****************************************************************************
002: * XMLUtils.java
003: * ****************************************************************************/
004:
005: /* J_LZ_COPYRIGHT_BEGIN *******************************************************
006: * Copyright 2006-2007 Laszlo Systems, Inc. All Rights Reserved. *
007: * Use is subject to license terms. *
008: * J_LZ_COPYRIGHT_END *********************************************************/
009:
010: package org.openlaszlo.js2doc;
011:
012: import java.util.*;
013: import java.io.*;
014: import java.util.logging.*;
015: import javax.xml.transform.*;
016: import javax.xml.transform.dom.*;
017: import javax.xml.transform.stream.*;
018: import javax.xml.parsers.DocumentBuilderFactory;
019: import org.custommonkey.xmlunit.*;
020: import org.openlaszlo.sc.parser.*;
021: import org.w3c.dom.*;
022:
023: public class JS2DocUtils {
024:
025: static private Logger logger = Logger
026: .getLogger("org.openlaszlo.js2doc");
027:
028: static class InternalError extends RuntimeException {
029:
030: SimpleNode node;
031:
032: /** Constructs an instance.
033: * @param message a string
034: * @param node offending parse node
035: */
036: public InternalError(String message, SimpleNode node) {
037: super (message);
038: this .node = node;
039: }
040: }
041:
042: public static String xmlToString(org.w3c.dom.Node node)
043: throws RuntimeException {
044: String stringResult = null;
045: try {
046: Source source = new DOMSource(node);
047: StringWriter stringWriter = new StringWriter();
048: Result result = new StreamResult(stringWriter);
049: TransformerFactory factory = TransformerFactory
050: .newInstance();
051: Transformer transformer = factory.newTransformer();
052: transformer.transform(source, result);
053: stringResult = stringWriter.getBuffer().toString();
054: } catch (TransformerConfigurationException e) {
055: e.printStackTrace();
056: throw new RuntimeException(
057: "Unable to instantiate XML Transformer");
058: } catch (TransformerException e) {
059: e.printStackTrace();
060: throw new RuntimeException("Error in XML Transformer");
061: }
062: return stringResult;
063: }
064:
065: public static void xmlToFile(org.w3c.dom.Node node, String filename)
066: throws RuntimeException {
067: try {
068: // Prepare the DOM document for writing
069: Source source = new DOMSource(node);
070:
071: // Prepare the output file
072: File file = new File(filename);
073: Result result = new StreamResult(file);
074:
075: // Write the DOM document to the file
076: Transformer xformer = TransformerFactory.newInstance()
077: .newTransformer();
078: xformer.transform(source, result);
079: } catch (TransformerConfigurationException e) {
080: e.printStackTrace();
081: throw new RuntimeException(
082: "Unable to instantiate XML Transformer");
083: } catch (TransformerException e) {
084: e.printStackTrace();
085: throw new RuntimeException("Error in XML Transformer");
086: }
087: }
088:
089: static public void setXMLContent(org.w3c.dom.Element node,
090: String content) {
091:
092: // Wrap the fragment in an arbitrary element
093: content = "<fragment>" + content + "</fragment>";
094:
095: try {
096: // Create a DOM builder and parse the fragment
097: DocumentBuilderFactory factory = DocumentBuilderFactory
098: .newInstance();
099: factory.setValidating(false);
100: Document d = factory.newDocumentBuilder().parse(
101: new org.xml.sax.InputSource(new StringReader(
102: content)));
103:
104: // Import the nodes of the new document into doc so that they
105: // will be compatible with doc
106: Document doc = node.getOwnerDocument();
107: org.w3c.dom.Node fragNode = doc.importNode(d
108: .getDocumentElement(), true);
109:
110: // Create the document fragment node to hold the new nodes
111: DocumentFragment docfrag = doc.createDocumentFragment();
112:
113: // Move the nodes into the fragment
114: while (fragNode.hasChildNodes()) {
115: docfrag.appendChild(fragNode.removeChild(fragNode
116: .getFirstChild()));
117: }
118:
119: node.appendChild(docfrag);
120: } catch (java.io.IOException e) {
121: logger.warning("Could not parse comment '" + content + "'");
122: e.printStackTrace();
123: } catch (javax.xml.parsers.ParserConfigurationException e) {
124: logger.warning("Could not parse comment '" + content + "'");
125: e.printStackTrace();
126: } catch (org.xml.sax.SAXException e) {
127: logger.warning("Could not parse comment '" + content + "'");
128: e.printStackTrace();
129: }
130: }
131:
132: static public org.w3c.dom.Element findFirstChildElementWithAttribute(
133: org.w3c.dom.Element docNode, String tagName,
134: String attrName, String name) {
135: org.w3c.dom.Element foundNode = null;
136: org.w3c.dom.NodeList childNodes = docNode.getChildNodes();
137: final int n = childNodes.getLength();
138: for (int i = 0; i < n; i++) {
139: org.w3c.dom.Node childNode = childNodes.item(i);
140: if (childNode instanceof org.w3c.dom.Element
141: && childNode.getNodeName().equals(tagName)) {
142: String eName = ((org.w3c.dom.Element) childNode)
143: .getAttribute(attrName);
144: if (eName != null && eName.equals(name)) {
145: foundNode = (org.w3c.dom.Element) childNode;
146: break;
147: }
148: }
149: }
150: return foundNode;
151: }
152:
153: static public org.w3c.dom.Node firstChildNodeWithName(
154: org.w3c.dom.Node node, String name) {
155: org.w3c.dom.Node foundNode = null;
156: org.w3c.dom.NodeList childNodes = node.getChildNodes();
157: final int n = childNodes.getLength();
158: for (int i = 0; i < n; i++) {
159: org.w3c.dom.Node childNode = childNodes.item(i);
160: if (childNode.getNodeName().equals(name)) {
161: foundNode = childNode;
162: break;
163: }
164: }
165: return foundNode;
166: }
167:
168: static void appendToAttribute(org.w3c.dom.Element node,
169: String attr, String value) {
170: String oldvalue = node.getAttribute(attr);
171: if (oldvalue == null || oldvalue.length() == 0)
172: node.setAttribute(attr, value.trim());
173: else
174: node.setAttribute(attr, oldvalue + " " + value.trim());
175: }
176:
177: static void describeConditionalState(ConditionalState state,
178: org.w3c.dom.Element docNode) {
179: if (state.inferredValue == ConditionalState.indeterminateValue) {
180: Set includeSet = new HashSet();
181: Set excludeSet = new HashSet();
182:
183: state.describeExclusiveConditions(includeSet);
184:
185: if (includeSet.isEmpty() == false) {
186: docNode.setAttribute("runtimes",
187: optionsToString(includeSet));
188: }
189:
190: includeSet.clear();
191:
192: state.describeIndependentConditions(includeSet, excludeSet);
193:
194: if (includeSet.isEmpty() == false) {
195: docNode.setAttribute("includebuilds",
196: optionsToString(includeSet));
197: }
198:
199: if (excludeSet.isEmpty() == false) {
200: docNode.setAttribute("excludebuilds",
201: optionsToString(excludeSet));
202: }
203: }
204: }
205:
206: static ConditionalState conditionalStateFromElement(
207: org.w3c.dom.Element propertyOwner, Set exclusiveOptions,
208: List independentOptions) {
209: String runtimes = propertyOwner.getAttribute("runtimes");
210: String includebuilds = propertyOwner
211: .getAttribute("includebuilds");
212: String excludebuilds = propertyOwner
213: .getAttribute("excludebuilds");
214:
215: ConditionalState newState = new ConditionalState(
216: ConditionalState.trueValue, exclusiveOptions,
217: independentOptions);
218:
219: if (runtimes != null) {
220: Scanner sc = new Scanner(runtimes);
221: while (sc.hasNext()) {
222: String option = sc.next();
223: newState.addTrueCase(option);
224: }
225: }
226: if (includebuilds != null) {
227: Scanner sc = new Scanner(includebuilds);
228: while (sc.hasNext()) {
229: String option = sc.next();
230: newState.addTrueCase(option);
231: }
232: }
233: if (excludebuilds != null) {
234: Scanner sc = new Scanner(excludebuilds);
235: while (sc.hasNext()) {
236: String option = sc.next();
237: newState.addFalseCase(option);
238: }
239: }
240:
241: return newState;
242: }
243:
244: static String derivePropertyID(org.w3c.dom.Node propertyOwner,
245: String propertyName, ConditionalState state) {
246: String objectID = null;
247: org.w3c.dom.Node parentNode = propertyOwner;
248: while (parentNode != null
249: && parentNode instanceof org.w3c.dom.Element) {
250: org.w3c.dom.Element ownerBinding = (org.w3c.dom.Element) parentNode;
251: if (ownerBinding.hasAttribute("id")) {
252: objectID = ownerBinding.getAttribute("id");
253: break;
254: }
255: parentNode = parentNode.getParentNode();
256: }
257: String classPrefix = (objectID != null) ? (objectID + ".") : "";
258: String conditionSuffix = "";
259: if (state != null
260: && state.inferredValue == ConditionalState.indeterminateValue)
261: conditionSuffix = state.toString();
262: return classPrefix + propertyName + conditionSuffix;
263: }
264:
265: static String optionsToString(Collection options) {
266: List c = new ArrayList(options);
267: Collections.sort(c);
268: String s = "";
269: for (Iterator iter = c.iterator(); iter.hasNext();) {
270: if (s != "")
271: s += " ";
272: s += (String) iter.next();
273: }
274: return s;
275: }
276:
277: static String nodeLocationInfo(SimpleNode parseNode) {
278: return parseNode.getFilename() + ": "
279: + parseNode.getLineNumber() + ", "
280: + parseNode.getColumnNumber();
281: }
282:
283: static String nodeDescription(SimpleNode parseNode) {
284: if (parseNode instanceof ASTIdentifier) {
285: return ((ASTIdentifier) parseNode).getName();
286: } else if (parseNode instanceof ASTLiteral) {
287: return ((ASTLiteral) parseNode).getValue().toString();
288: } else
289: return "";
290: }
291:
292: static void debugPrintNode(SimpleNode parseNode) {
293: debugPrintNode(parseNode, 0, 0);
294: }
295:
296: static void debugPrintNode(SimpleNode parseNode, int level,
297: int index) {
298: String c = parseNode.getComment();
299: System.err.println("node: (" + level + ">>" + index + ") "
300: + parseNode.getClass().getName() + " "
301: + nodeDescription(parseNode) + " ("
302: + nodeLocationInfo(parseNode) + ")");
303: SimpleNode[] children = parseNode.getChildren();
304: for (int i = 0; i < children.length; i++) {
305: debugPrintNode(children[i], level + 1, i);
306: }
307: }
308:
309: static void checkChildrenLowerBounds(SimpleNode node, int min,
310: int expectedMax, String methodName) {
311: SimpleNode[] children = node.getChildren();
312:
313: if (children.length < min) {
314: logger.throwing("JS2Doc", methodName, new InternalError(
315: "Too few child nodes in "
316: + node.getClass().getName(), node));
317: } else if (expectedMax > 0 && children.length > expectedMax) {
318: logger.fine("Unexpected number of child nodes in "
319: + node.getClass().getName());
320: }
321: }
322:
323: }
|