/* # Copyright (c) 2007 Laurent Morissette # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFINTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIEDOR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE., INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS */ package com.mor.blogengine.xpath; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.dom4j.tree.DefaultAttribute; /** * * @author Laurent * Builder class that can supply either XPATH 1.0 and 2.0 if VERSION_SUPPORT is set to 2.0f */ public class XPathExpressionBuilder { /** * */ public static final float VERSION_SUPPORT = 1.0f; final boolean considerPrefix = false; /** * Namespace prefix as i.e 'site' */ private String mPrefix = null; /** * Root node */ private String mRootNode = null; /** *list of child nodes requiered until reaching searched */ private String[] mSubNodeList = null; /** *Searched nodes attributes */ private String[] mAttributes = null; /** *
* Build an XPATH expression builder Object with Following parameters
* @param pPrefix an element can have a prefix or not i.e <XXX:YYY>
* @param pRootNode Main node of document
* @param pNodeList sub-Node list that compose a tree i.e Node1,Node2,Node3
* @param pAttributesList final node attributes list
* Usage:
*
* String prefix="aPrfix";
* String root="Root";
* List nodes=new Arraylist();
* nodes.add("Node1");
* Attribute attrib=new Attribute("number","1");
* List attributes=new ArrayList();
* attributes.add(attrib);
* //in the end with would do:
* String expression=new XPathExpressionBuilder(prefix,root,nodes,attributes).compileExpression();
* //expression would then be:
* /aPrefix:root//aPrefix:Node1[@nuber="1"]
*
*
*/
public XPathExpressionBuilder(String pPrefix, String pRootNode, List pNodeList, List pAttributesList) {
if (considerPrefix) {
setPrefix(pPrefix);
}
setRootNode(pRootNode);
setNodes(pNodeList);
addAttributesList(pAttributesList);
}
/**
* Rien
*/
public XPathExpressionBuilder() {
}
/**
*
* @param pPrefix
*/
private void setPrefix(String pPrefix) {
mPrefix = pPrefix;
}
/**
*
* @param pNodes
*/
private void setNodes( final List pNodes) {
if (mSubNodeList == null) {
mSubNodeList = convertNodesListToStringArray(pNodes);
}
}
/**
*
* @param pRootNode
*/
private void setRootNode(String pRootNode) {
mRootNode = pRootNode;
}
/**
*
* @param pAttribList
*/
private void addAttributesList( final List pAttribList) {
if (pAttribList != null) {
mAttributes = convertAttributeListToStringArray(pAttribList);
}
}
/**
*
* @return
*/
public String compileExpression() {
String lExpression = new String();
if (considerPrefix) {
lExpression += "/" + mPrefix + ":" + mRootNode;
} else {
lExpression += "/" + mRootNode;
}
lExpression += addNodesToExpression(considerPrefix);
lExpression += addAttributesToExpression();
return lExpression;
}
/**
*
* @param pList
* @return
*/
private String[] convertAttributeListToStringArray(List pList) {
Object[] lAttribArray = null;
Iterator lKeysIt = pList.listIterator();
ArrayList lList = new ArrayList();
while (lKeysIt.hasNext()) {
DefaultAttribute lAttribute = (DefaultAttribute) lKeysIt.next();
String lCurrentKey = lAttribute.getName();
String lCurrentValue = lAttribute.getValue();
String lKeyValueString = formatKeyAttributeValue(lCurrentKey, lCurrentValue);
lList.add(lKeyValueString);
lAttribArray = lList.toArray();
Arrays.sort(lAttribArray);
}
return transferArrayData(lAttribArray);
}
/**
*
* @param pList
* @return
*/
private String[] convertNodesListToStringArray( final List pList) {
return transferArrayData(pList.toArray());
}
/**
*
* @param a
* @return
*/
private String[] transferArrayData(final Object[] a) {
String[] strArray = new String[a.length];
for (int currentDataIndex = 0; currentDataIndex < strArray.length; currentDataIndex++) {
strArray[currentDataIndex] = a[currentDataIndex].toString();
}
return strArray;
}
/**
*
* @return
*/
private String addNodesToExpression( final boolean includePrefix) {
int lLength = mSubNodeList.length;
String nodes = new String();
if (includePrefix) {//Include prefix if ns is present
if (lLength > 1) { //check nodes count
for (int currenNodeIndex = 0; currenNodeIndex < lLength; currenNodeIndex++) {
nodes += ("//" + mPrefix + ":" + mSubNodeList[currenNodeIndex]);
}
} else {
nodes += ("//" + mPrefix + ":" + mSubNodeList[0]);
}
} else {
if (lLength > 1) {
for (int i = 0; i < lLength; i++) {
nodes += ("//" + mSubNodeList[i]);
}
} else {
nodes += ("//" + mSubNodeList[0]);
}
}
return nodes;
}
/**
*
* @return
*/
private String addAttributesToExpression() {
if (mAttributes != null) {
int lLength = mAttributes.length;
String lExpression = new String();
if (lLength > 1) {
lExpression += "[";
for (int currentAttributeIndex = 0; currentAttributeIndex < lLength; currentAttributeIndex++) {
if (currentAttributeIndex == lLength - 1) {
lExpression += ("@" + mAttributes[currentAttributeIndex]);
} else {
lExpression += ("@" + mAttributes[currentAttributeIndex] + " and ");
}
}
lExpression += "]";
} else {
lExpression += ("[@" + mAttributes[0] + "]");
}
return lExpression;
}
return "";
}
/**
*
* @param pValue
* @return
*/
private String formatKeyAttributeValue(String pKey, String pValue) {
String lKeyValueString = "";
// strong typing was introduced in XPATH 2.0 only
if (VERSION_SUPPORT == 2.0f) {
if (pKey.equalsIgnoreCase("ID")) {
lKeyValueString = pKey + "=" + "'" + (pValue) + "'";
} else if (isNumber(pValue)) {
lKeyValueString = pKey + "=" + "xs:double(" + pValue + ")";
} else if (isBolean(pValue)) {
lKeyValueString = pKey + "=" + "xs:boolean(" + pValue + ")";
}
} else {
lKeyValueString = pKey + "=" + "'" + (pValue) + "'";
}
return lKeyValueString;
}
/**
*
* @param pValue
* @return
*/
private boolean isNumber(String pValue) {
try {
Integer.parseInt(pValue);
return true;
} catch (NumberFormatException e) {
return false;
}
}
/**
*
* @param pValue
* @return
*/
private boolean isBolean(String pValue) {
return Boolean.parseBoolean(pValue);
}
}