Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
Copyright 2005-2013 The Kuali Foundation Licensed under the Educational Community License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.opensource.org/licenses/ecl2.php Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
 
 package org.kuali.rice.kew.xml.xstream;
 
 import java.util.List;
 
 
Evaluates simple XPath expressions to follow paths through a document generated by XStream which uses "reference" elements to handle circular and duplicate references. For example, an XML document generated from XStream might look like the following:
<test>
   hello
   
     
   
 </test>

In the above case, the XPath expression /test/a would result in the "hello" text but the XPath expression /test/b/a would result in the empty string. However, if the evaluator below is mapped as an XPath function, than it could be used as follows on the second expression to produce the desired result of "hello": xstreamsafe('/test/b/a', root())

Author(s):
Kuali Rice Team (rice.collab@kuali.org)
 
 public class XStreamSafeEvaluator {
 	
 	private static final String MATCH_ANY = "//";
 	private static final String MATCH_ROOT = "/";
 	private static final String MATCH_CURRENT = ".";
 	private static final String XSTREAM_REFERENCE_ATTRIBUTE = "reference";
 	private XPath xpath;
 
 	public XStreamSafeEvaluator() {}
 	
 	public XStreamSafeEvaluator(XPath xpath) {
 		this. = xpath;
 	}
Evaluates the given XPath expression against the given Node while following reference attributes on Nodes in a way which is compatible with the XStream library.

Throws:
javax.xml.xpath.XPathExpressionException if there was a problem evaluation the XPath expression.
 
 	public NodeList evaluate(String xPathExpressionNode rootSearchNodethrows XPathExpressionException {
 		XPath xpathEval = this.getXpath();
 		List segments = new ArrayList();
 		parseExpression(segmentsxPathExpressiontrue);
 		SimpleNodeList nodes = new SimpleNodeList();
 		nodes.getList().add(rootSearchNode);
 		for (Iterator iterator = segments.iterator(); iterator.hasNext();) {
 			SimpleNodeList newNodeList = new SimpleNodeList();
 			XPathSegment expression = (XPathSegmentiterator.next();
 			for (Iterator nodeIterator = nodes.getList().iterator(); nodeIterator.hasNext();) {
 				Node node = (Node)nodeIterator.next();
 				node = resolveNodeReference(xpathEvalnode);
 				if (node != null) {
 					NodeList evalSet = (NodeList)xpathEval.evaluate(expression.getXPathExpression(), node.);
 					if (evalSet != null) {
 						for (int nodeIndex = 0; nodeIndex < evalSet.getLength(); nodeIndex++) {
 							Node newNode = evalSet.item(nodeIndex);
 							newNodeList.getList().add(newNode);
 						}
 					}
 				}
 			}
 			nodes = newNodeList;
 		}
 		// now, after we've reached "the end of the line" check our leaf nodes and resolve any XStream references on them
 		// TODO I noticed that the original implementation of this method was not doing the following work so I'm just tacking it on the end, there's
 		// probably a more elegent way to integrate it with the algorithm above...
 		SimpleNodeList newNodes = new SimpleNodeList();
 		for (Iterator iterator = nodes.getList().iterator(); iterator.hasNext();) {
			Node node = (Nodeiterator.next();
			newNodes.getList().add(resolveNodeReference(xpathEvalnode));
		}
		return newNodes;
	}

Parses the given XPath expression into a List of segments which can be evaluated in order.
	private void parseExpression(List segmentsString xPathExpressionboolean isInitialSegmentthrows XPathExpressionException {
		if (StringUtils.isEmpty(xPathExpression)) {
			return;
		}
		XPathSegment segment = isInitialSegment ? parseInitialSegment(xPathExpression) : parseNextSegment(xPathExpression);
		segments.add(segment);
		parseExpression(segmentsxPathExpression.substring(segment.getLength()), false);
	}
//	private XPathSegment parseNextSegment(String xPathExpression) throws XPathExpressionException {
//		int operatorLength = 2;
//		int firstIndex = xPathExpression.indexOf(MATCH_ANY);
//		if (firstIndex != 0) {
//			firstIndex = xPathExpression.indexOf(MATCH_CURRENT);
//			if (firstIndex != 0) {
//				operatorLength = 1;
//				firstIndex = xPathExpression.indexOf(MATCH_ROOT);				
//			}
//		}
//		// the operator should be at the beginning of the string
//		if (firstIndex != 0) {
//			throw new XPathExpressionException("Could not locate an appropriate ./, /, or // operator at the begginingg of the xpath segment: " + xPathExpression);
//		}
//		int nextIndex = xPathExpression.indexOf(MATCH_ANY, operatorLength);
//		if (nextIndex == -1) {
//			nextIndex = xPathExpression.indexOf(MATCH_ROOT, operatorLength);
//		}
//		if (nextIndex == -1) {
//			nextIndex = xPathExpression.length();
//		}
//		return new XPathSegment(xPathExpression.substring(0,operatorLength),
//				xPathExpression.substring(operatorLength, nextIndex));
//	}
Parses the next segment of the given XPath expression by grabbing the first segment off of the given xpath expression. The given xpath expression must start with either ./, /, or // otherwise an XPathExpressionException is thrown.
	private XPathSegment parseInitialSegment(String xPathExpressionthrows XPathExpressionException {
		// TODO we currently can't support expressions that start with .//
		if (xPathExpression.startsWith(+)) {
			throw new XPathExpressionException("XStream safe evaluator currenlty does not support expressions that start with " ++);
		}
		//int operatorLength = 3;
		//int firstIndex = xPathExpression.indexOf(MATCH_CURRENT+MATCH_ANY);
		//if (firstIndex != 0) {
			int operatorLength = 2;
			int firstIndex = xPathExpression.indexOf(+);
			if (firstIndex != 0) {
				firstIndex = xPathExpression.indexOf();
				if (firstIndex != 0) {
					operatorLength = 1;
					firstIndex = xPathExpression.indexOf();
				}
			}
		//}
		// the operator should be at the beginning of the string
		if (firstIndex != 0) {
			throw new XPathExpressionException("Could not locate an appropriate ./, /, or // operator at the begginingg of the xpath segment: " + xPathExpression);
		}
		int nextIndex = xPathExpression.indexOf(operatorLength);
		if (nextIndex == -1) {
			nextIndex = xPathExpression.length();
		}
		return new XPathSegment(xPathExpression.substring(0, operatorLength),
				xPathExpression.substring(operatorLengthnextIndex), true);
	}

Parses the next segment of the given XPath expression by grabbing the first segment off of the given xpath expression. The given xpath expression must start with / otherwise an XPathExpressionException is thrown. This is because the "next" segments represent the internal pieces in an XPath expression.
	private XPathSegment parseNextSegment(String xPathExpressionthrows XPathExpressionException {
		if (!xPathExpression.startsWith()) {
			throw new XPathExpressionException("Illegal xPath segment, the given segment is not a valid segment and should start with a '"++"'.  Value was: " + xPathExpression);
		}
		int operatorLength = .length();
		int nextIndex = xPathExpression.indexOf(operatorLength);
		if (nextIndex == -1) {
			nextIndex = xPathExpression.length();
		}
		return new XPathSegment(+xPathExpression.substring(operatorLengthnextIndex), false);
	}

Resolves the reference to a Node by checking for a "reference" attribute and returning the resolved node if it's there. The resolution happens by grabbing the value of the reference and evaluation it as an XPath expression against the given Node. If there is no reference attribute, the node passed in is returned. The method is recursive in the fact that it will continue to follow XStream "reference" attributes until it reaches a resolved node.
	private Node resolveNodeReference(XPath xpathNode nodethrows XPathExpressionException{
		NamedNodeMap attributes = node.getAttributes();
		if (attributes != null) {
			Node referenceNode = attributes.getNamedItem();
			if (referenceNode != null) {
				node = (Node)xpath.evaluate(referenceNode.getNodeValue(), node.);
				if (node != null) {
					node = resolveNodeReference(xpathnode);
else {
					throw new XPathExpressionException("Could not locate the node for the given XStream references expression: '" + referenceNode.getNodeValue() + "'");
				}
			}
		}
		return node;
	}

A single segment of an XPath expression.
	private class XPathSegment {
		private final String operator;
		private final String value;
		private final boolean isInitialSegment;
		public XPathSegment(String operatorString valueboolean isInitialSegment) {
			this. = operator;
			this. = value;
			// if it's not an initial segment then a '.' will preceed the operator and should not be counted in the length
			this. = isInitialSegment;
		}
		public int getLength() {
			// if it's not an initial segment then a '.' will preceed the operator and should not be counted in the length
				return .length() + .length() - 1;
			}
			return .length() + .length();
		}
Returns an XPath expression which can be evaluated in the context of the node returned by the previously executed segment.
			return +;
		}
	}

A simple NodeList implementation, as simple as it gets. This allows us to not be tied to any particular XML service provider's NodeList implementation.
	private class SimpleNodeList implements NodeList {
		private List nodes = new ArrayList();
		public Node item(int index) {
			return (Node).get(index);
		}
		public int getLength() {
			return .size();
		}
		public List getList() {
			return ;
		}
	}
	public XPath getXpath() {
		if (this. == null) {
			return XPathHelper.newXPath();
		}
		return ;
	}
	public void setXpath(XPath xpath) {
		this. = xpath;
	}
New to GrepCode? Check out our FAQ X