package client.net.sf.saxon.ce.tree.util; /** * ProcInstParser is used to parse pseudo-attributes within Processing Instructions * @author Michael H. Kay * @version 10 July 2000 */ public class ProcInstParser { /** * Class is never instantiated */ private ProcInstParser() { } /** * Get a pseudo-attribute. This is useful only if the processing instruction data part * uses pseudo-attribute syntax, which it does not have to. This syntax is as described * in the W3C Recommendation "Associating Style Sheets with XML Documents". * @return the value of the pseudo-attribute if present, or null if not */ public static String getPseudoAttribute(String content, String name) { int pos = 0; while (pos <= content.length()-4) { // minimum length of x="" int nextQuote = -1; for (int q=pos; q<content.length(); q++) { if (content.charAt(q)=='"' || content.charAt(q)=='\'') { nextQuote = q; break; } } if (nextQuote < 0) return null; int closingQuote = content.indexOf(content.charAt(nextQuote), nextQuote+1); if (closingQuote<0) return null; int nextName = content.indexOf(name, pos); if (nextName < 0) return null; if (nextName < nextQuote) { // check only spaces and equal signs between the name and the quote boolean found = true; for (int s = nextName + name.length(); s < nextQuote; s++) { char c = content.charAt(s); if (" \n\r\t".indexOf(c) < 0 && c != '=') { found=false; break; } } if (found) { String val = content.substring(nextQuote+1, closingQuote); String u = unescape(val); if (u == null) { // unescaping failed return val; } else { return u; } } } pos = closingQuote + 1; } return null; } /** * Interpret character references and built-in entity references. * @return value with character references and built-in entity references expanded. * If badly-formed or unrecognized references are found, return null */ private static String unescape(String value) { if (value.indexOf('&')<0) return value; FastStringBuffer sb = new FastStringBuffer(value.length()); for (int i=0; i<value.length(); i++) { char c = value.charAt(i); if (c=='&') { if (i+2 < value.length() && value.charAt(i+1)=='#') { if (value.charAt(i+2)=='x') { int x = i+3; int charval = 0; while (x<value.length() && value.charAt(x)!=';') { int digit = "0123456789abcdef".indexOf(value.charAt(x)); if (digit<0) { digit = "0123456789ABCDEF".indexOf(value.charAt(x)); } if (digit<0) { return null; } charval = charval * 16 + digit; x++; } char hexchar = (char)charval; sb.append(hexchar); i=x; } else { int x = i+2; int charval = 0; while (x<value.length() && value.charAt(x)!=';') { int digit = "0123456789".indexOf(value.charAt(x)); if (digit<0) { return null; } charval = charval * 10 + digit; x++; } char decchar = (char)charval; sb.append(decchar); i=x; } } else if (value.substring(i+1).startsWith("lt;")) { sb.append('<'); i+=3; } else if (value.substring(i+1).startsWith("gt;")) { sb.append('>'); i+=3; } else if (value.substring(i+1).startsWith("amp;")) { sb.append('&'); i+=4; } else if (value.substring(i+1).startsWith("quot;")) { sb.append('"'); i+=5; } else if (value.substring(i+1).startsWith("apos;")) { sb.append('\''); i+=5; } else { return null; } } else { sb.append(c); } } return sb.toString(); } } // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.