/* ****************************************************************************** * Copyright (C) 2004-2012, International Business Machines Corporation and * * others. All Rights Reserved. * ****************************************************************************** */ /** * @author Ram Viswanadha * * This tool validates xml against DTD ... IE 6 does not do a good job */ package org.unicode.cldr.util; public class XPathTokenizer { char[] xpath; int current; public XPathTokenizer(StringBuffer path) { this(path.toString()); } public XPathTokenizer(StringBuilder path) { this(path.toString()); } public XPathTokenizer(String path) { xpath = path.toCharArray(); if (path.indexOf("..") == 0) { current = 0; } else { // this is absolute // since xpath starts with "//" current = 2; } } public String nextToken() { boolean inquote = false; String retval; int save = current; while (current < xpath.length) { switch (xpath[current]) { case '\'': inquote = (inquote == true) ? false : true; current++; break; case '/': if (inquote == false) { retval = new String(xpath, save, (current - save)); current++; // skip past the separator return retval; } // fall through default: current++; } } if (current == xpath.length) { retval = new String(xpath, save, (current - save)); current++; return retval; } return null; } public static StringBuffer deleteToken(StringBuffer xpath) { int length = xpath.length(); int current = length - 1; while (current > 0) { boolean inquote = false; switch (xpath.charAt(current)) { case '\'': inquote = (inquote == true) ? false : true; current--; break; case '/': if (inquote == false) { if (current < length) { xpath.delete(current, length); } return xpath; } // fall through default: current--; } } return xpath; } public static StringBuilder deleteToken(StringBuilder xpath) { int length = xpath.length(); int current = length - 1; while (current > 0) { boolean inquote = false; switch (xpath.charAt(current)) { case '\'': inquote = (inquote == true) ? false : true; current--; break; case '/': if (inquote == false) { if (current < length) { xpath.delete(current, length); } return xpath; } // fall through default: current--; } } return xpath; } /** * This method will try to convert a relative xpath to absolute * xpath. * TODO: The method will only resolve relative tokens in the begining * of the string. Try to handle embedded ".." * * @param xpath * @param fullPath * @return * @deprecated - use version that takes StringBuilder instead */ @Deprecated public static StringBuffer relativeToAbsolute(String xpath, StringBuffer fullPath) { if (!xpath.startsWith("..")) { fullPath.setLength(0); fullPath.append(xpath); return fullPath; } XPathTokenizer tokenizer = new XPathTokenizer(xpath); String token = tokenizer.nextToken(); StringBuffer retVal = new StringBuffer(); retVal.append(fullPath); while (token.equals("..")) { deleteToken(retVal); token = tokenizer.nextToken(); } while (token != null) { retVal.append("/"); retVal.append(token); token = tokenizer.nextToken(); } return retVal; } public static StringBuilder relativeToAbsolute(String xpath, StringBuilder fullPath) { if (!xpath.startsWith("..")) { fullPath.setLength(0); fullPath.append(xpath); return fullPath; } XPathTokenizer tokenizer = new XPathTokenizer(xpath); String token = tokenizer.nextToken(); StringBuilder retVal = new StringBuilder(); retVal.append(fullPath); while (token.equals("..")) { deleteToken(retVal); token = tokenizer.nextToken(); } while (token != null) { retVal.append("/"); retVal.append(token); token = tokenizer.nextToken(); } return retVal; } }