001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019:
020: package org.netbeans.modules.xml.xpath.ext.visitor.impl;
021:
022: import javax.xml.namespace.NamespaceContext;
023: import javax.xml.namespace.QName;
024: import org.netbeans.modules.xml.xpath.ext.CoreOperationType;
025: import org.netbeans.modules.xml.xpath.ext.LocationStep;
026: import org.netbeans.modules.xml.xpath.ext.XPathCoreFunction;
027: import org.netbeans.modules.xml.xpath.ext.XPathCoreOperation;
028: import org.netbeans.modules.xml.xpath.ext.XPathExpression;
029: import org.netbeans.modules.xml.xpath.ext.XPathExpressionPath;
030: import org.netbeans.modules.xml.xpath.ext.XPathExtensionFunction;
031: import org.netbeans.modules.xml.xpath.ext.XPathLocationPath;
032: import org.netbeans.modules.xml.xpath.ext.XPathModel;
033: import org.netbeans.modules.xml.xpath.ext.XPathNumericLiteral;
034: import org.netbeans.modules.xml.xpath.ext.XPathPredicateExpression;
035: import org.netbeans.modules.xml.xpath.ext.XPathStringLiteral;
036: import org.netbeans.modules.xml.xpath.ext.XPathVariableReference;
037: import org.netbeans.modules.xml.xpath.ext.metadata.OperationMetadata;
038: import org.netbeans.modules.xml.xpath.ext.visitor.XPathVisitorAdapter;
039:
040: /**
041: * Implements the XPathVisitor interface to generate a string representation
042: * of an expression.
043: *
044: * @author sbyn
045: * @author nk160297
046: * @version
047: */
048: public class ExpressionWriter extends XPathVisitorAdapter {
049:
050: /** The string buffer. */
051: private StringBuffer mBuffer;
052:
053: private XPathExpression mParentExpr;
054: private XPathModel mXPathModel;
055:
056: /** Constructor. */
057: public ExpressionWriter(XPathModel xPathModel) {
058: mBuffer = new StringBuffer();
059: mXPathModel = xPathModel;
060: }
061:
062: /**
063: * Gets the string representation of the expression.
064: * @return the string representation
065: */
066: public String getString() {
067: return mBuffer.toString();
068: }
069:
070: /**
071: * Visits an location step.
072: * @param locationStep to visit
073: */
074: @Override
075: public void visit(LocationStep locationStep) {
076: mBuffer.append(locationStep.getString());
077: XPathPredicateExpression[] predicates = locationStep
078: .getPredicates();
079: if (predicates != null) {
080: for (int j = 0, length = predicates.length; j < length; j++) {
081: predicates[j].accept(this );
082: }
083: }
084: }
085:
086: @Override
087: public void visit(XPathPredicateExpression predicate) {
088: XPathExpression predicateExpression = predicate.getPredicate();
089: if (predicateExpression != null) {
090: mBuffer.append('[');
091: mParentExpr = predicate;
092: predicateExpression.accept(this );
093: mBuffer.append(']');
094: }
095: }
096:
097: @Override
098: public void visit(XPathVariableReference vReference) {
099: mBuffer.append("$" + vReference.getVariableName());
100: }
101:
102: /**
103: * Visits a string literal.
104: * @param stringLiteral to visit
105: */
106: @Override
107: public void visit(XPathStringLiteral stringLiteral) {
108:
109: // quotes in literal strings for xpath 1.0 basically work like this:
110: // 1. we can either quote strings with single or double quotes
111: // 2. quote the string with single quotes if the string contains double quotes
112: // i.e. 'the "correct" way', 'the 'incorrect' way'
113: // 3. quote the string with double quotes if the string contains single quotes
114: // i.e. "the 'correct' way", "the "incorrect" way"
115: // - josh
116:
117: String literal = stringLiteral.getValue();
118: boolean isStringQuoted = false;
119: if (literal.length() >= 2) {
120: if (literal.startsWith("'") && literal.endsWith("'")) {
121: isStringQuoted = true;
122: } else if (literal.startsWith("\"")
123: && literal.endsWith("\"")) {
124: isStringQuoted = true;
125: }
126: }
127:
128: if (isStringQuoted) {
129: // if literal is already quoted, do not quote the literal
130: mBuffer.append(literal);
131: } else {
132: if (literal.indexOf("'") >= 0) {
133: // string contains a single-quote,
134: // it must be quoted with double-quotes
135: mBuffer.append("\"");
136: mBuffer.append(literal);
137: mBuffer.append("\"");
138: } else {
139: // quote the string with single-quotes by default
140: mBuffer.append("'");
141: mBuffer.append(literal);
142: mBuffer.append("'");
143: }
144: }
145:
146: }
147:
148: /**
149: * Visits a numeric literal.
150: * @param numericLiteral to visit
151: */
152: @Override
153: public void visit(XPathNumericLiteral numericLiteral) {
154: mBuffer.append(numericLiteral.getValue().toString());
155: }
156:
157: /**
158: * Visits a location path.
159: * @param locationPath to visit
160: */
161: @Override
162: public void visit(XPathLocationPath locationPath) {
163: LocationStep[] steps = locationPath.getSteps();
164: if (locationPath.getAbsolute()) {
165: mBuffer.append(LocationStep.STEP_SEPARATOR);
166: }
167: for (int i = 0; i < steps.length; i++) {
168: if (i != 0) {
169: mBuffer.append(LocationStep.STEP_SEPARATOR);
170: }
171: mParentExpr = locationPath;
172: steps[i].accept(this );
173: }
174: }
175:
176: /**
177: * Visits a expression path.
178: * @param locationPath to visit
179: */
180: @Override
181: public void visit(XPathExpressionPath expressionPath) {
182: XPathExpression rootExpression = expressionPath
183: .getRootExpression();
184: if (rootExpression != null) {
185: mParentExpr = expressionPath;
186: rootExpression.accept(this );
187: }
188: //
189: LocationStep[] steps = expressionPath.getSteps();
190: for (int i = 0; i < steps.length; i++) {
191: mBuffer.append(LocationStep.STEP_SEPARATOR);
192: mParentExpr = expressionPath;
193: steps[i].accept(this );
194: }
195: }
196:
197: /**
198: * Visits a core operation.
199: * @param coreOperation to visit
200: */
201: @Override
202: public void visit(XPathCoreOperation coreOperation) {
203: if (CoreOperationType.OP_NEGATIVE == coreOperation
204: .getOperationType()) {
205: mBuffer.append(coreOperation.getOperationType()
206: .getMetadata().getName());
207: if (coreOperation.getChildCount() > 0) {
208: XPathExpression firstArg = coreOperation.getChild(0);
209: mParentExpr = coreOperation;
210: firstArg.accept(this );
211: }
212: } else {
213: boolean isBracketsRequired = false;
214: OperationMetadata metadata = coreOperation
215: .getOperationType().getMetadata();
216: if (mParentExpr != null
217: && mParentExpr instanceof XPathCoreOperation) {
218: int parentPrecedence = ((XPathCoreOperation) mParentExpr)
219: .getOperationType().getMetadata()
220: .getPrecedenceLevel();
221: int myPrecedence = metadata.getPrecedenceLevel();
222: isBracketsRequired = parentPrecedence > myPrecedence;
223: }
224: //
225: if (isBracketsRequired) {
226: mBuffer.append("(");
227: }
228: //
229: boolean isFirst = true;
230: for (XPathExpression childExpr : coreOperation
231: .getChildren()) {
232: if (isFirst) {
233: isFirst = false;
234: } else {
235: mBuffer.append(' ');
236: mBuffer.append(metadata.getName());
237: mBuffer.append(' ');
238: }
239: //
240: mParentExpr = coreOperation;
241: childExpr.accept(this );
242: }
243: //
244: if (isBracketsRequired) {
245: mBuffer.append(")");
246: }
247: }
248: }
249:
250: /**
251: * Visits a core function.
252: * @param coreFunction to visit
253: */
254: @Override
255: public void visit(XPathCoreFunction coreFunction) {
256: mBuffer.append(coreFunction.getName());
257: mBuffer.append('(');
258: boolean isFirst = true;
259: for (XPathExpression expr : coreFunction.getChildren()) {
260: if (isFirst) {
261: isFirst = false;
262: } else {
263: mBuffer.append(", ");
264: }
265: //
266: mParentExpr = coreFunction;
267: expr.accept(this );
268: }
269: mBuffer.append(')');
270: }
271:
272: /**
273: * Visits an extension function.
274: * @param extensionFunction to visit
275: */
276: @Override
277: public void visit(XPathExtensionFunction extensionFunction) {
278: QName extFuncQName = extensionFunction.getName();
279: String prefix = extFuncQName.getPrefix();
280: String localPart = extFuncQName.getLocalPart();
281: //
282: if (prefix == null || prefix.length() == 0) {
283: prefix = calculateFuncPrefix(extFuncQName);
284: }
285: //
286: if (prefix == null || prefix.length() == 0) {
287: mBuffer.append(localPart);
288: } else {
289: mBuffer.append(prefix + ":" + localPart);
290: }
291: //
292: mBuffer.append('(');
293: boolean isFirst = true;
294: for (XPathExpression expr : extensionFunction.getChildren()) {
295: if (isFirst) {
296: isFirst = false;
297: } else {
298: mBuffer.append(", ");
299: }
300: //
301: mParentExpr = extensionFunction;
302: expr.accept(this );
303: }
304: mBuffer.append(')');
305: }
306:
307: public String calculateFuncPrefix(QName funcQName) {
308: if (mXPathModel != null) {
309: NamespaceContext nsContext = mXPathModel
310: .getNamespaceContext();
311: if (nsContext != null) {
312: String nsUri = funcQName.getNamespaceURI();
313: return nsContext.getPrefix(nsUri);
314: }
315: }
316: return null;
317: }
318:
319: }
|