| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache 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.apache.org/licenses/LICENSE-2.0 |
| * |
| * 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. |
| */ |
| /* |
| * $Id$ |
| */ |
| package org.apache.xalan.lib; |
| |
| import java.util.StringTokenizer; |
| |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.FactoryConfigurationError; |
| import javax.xml.parsers.ParserConfigurationException; |
| |
| import org.apache.xpath.NodeSet; |
| |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.w3c.dom.Text; |
| |
| /** |
| * This class contains EXSLT strings extension functions. |
| * |
| * It is accessed by specifying a namespace URI as follows: |
| * <pre> |
| * xmlns:str="http://exslt.org/strings" |
| * </pre> |
| * The documentation for each function has been copied from the relevant |
| * EXSLT Implementer page. |
| * |
| * @see <a href="http://www.exslt.org/">EXSLT</a> |
| |
| * @xsl.usage general |
| */ |
| public class ExsltStrings extends ExsltBase |
| { |
| /** |
| * The str:align function aligns a string within another string. |
| * <p> |
| * The first argument gives the target string to be aligned. The second argument gives |
| * the padding string within which it is to be aligned. |
| * <p> |
| * If the target string is shorter than the padding string then a range of characters |
| * in the padding string are repaced with those in the target string. Which characters |
| * are replaced depends on the value of the third argument, which gives the type of |
| * alignment. It can be one of 'left', 'right' or 'center'. If no third argument is |
| * given or if it is not one of these values, then it defaults to left alignment. |
| * <p> |
| * With left alignment, the range of characters replaced by the target string begins |
| * with the first character in the padding string. With right alignment, the range of |
| * characters replaced by the target string ends with the last character in the padding |
| * string. With center alignment, the range of characters replaced by the target string |
| * is in the middle of the padding string, such that either the number of unreplaced |
| * characters on either side of the range is the same or there is one less on the left |
| * than there is on the right. |
| * <p> |
| * If the target string is longer than the padding string, then it is truncated to be |
| * the same length as the padding string and returned. |
| * |
| * @param targetStr The target string |
| * @param paddingStr The padding string |
| * @param type The type of alignment |
| * |
| * @return The string after alignment |
| */ |
| public static String align(String targetStr, String paddingStr, String type) |
| { |
| if (targetStr.length() >= paddingStr.length()) |
| return targetStr.substring(0, paddingStr.length()); |
| |
| if (type.equals("right")) |
| { |
| return paddingStr.substring(0, paddingStr.length() - targetStr.length()) + targetStr; |
| } |
| else if (type.equals("center")) |
| { |
| int startIndex = (paddingStr.length() - targetStr.length()) / 2; |
| return paddingStr.substring(0, startIndex) + targetStr + paddingStr.substring(startIndex + targetStr.length()); |
| } |
| // Default is left |
| else |
| { |
| return targetStr + paddingStr.substring(targetStr.length()); |
| } |
| } |
| |
| /** |
| * See above |
| */ |
| public static String align(String targetStr, String paddingStr) |
| { |
| return align(targetStr, paddingStr, "left"); |
| } |
| |
| /** |
| * The str:concat function takes a node set and returns the concatenation of the |
| * string values of the nodes in that node set. If the node set is empty, it returns |
| * an empty string. |
| * |
| * @param nl A node set |
| * @return The concatenation of the string values of the nodes in that node set |
| */ |
| public static String concat(NodeList nl) |
| { |
| StringBuffer sb = new StringBuffer(); |
| for (int i = 0; i < nl.getLength(); i++) |
| { |
| Node node = nl.item(i); |
| String value = toString(node); |
| |
| if (value != null && value.length() > 0) |
| sb.append(value); |
| } |
| |
| return sb.toString(); |
| } |
| |
| /** |
| * The str:padding function creates a padding string of a certain length. |
| * The first argument gives the length of the padding string to be created. |
| * The second argument gives a string to be used to create the padding. This |
| * string is repeated as many times as is necessary to create a string of the |
| * length specified by the first argument; if the string is more than a character |
| * long, it may have to be truncated to produce the required length. If no second |
| * argument is specified, it defaults to a space (' '). If the second argument is |
| * an empty string, str:padding returns an empty string. |
| * |
| * @param length The length of the padding string to be created |
| * @param pattern The string to be used as pattern |
| * |
| * @return A padding string of the given length |
| */ |
| public static String padding(double length, String pattern) |
| { |
| if (pattern == null || pattern.length() == 0) |
| return ""; |
| |
| StringBuffer sb = new StringBuffer(); |
| int len = (int)length; |
| int numAdded = 0; |
| int index = 0; |
| while (numAdded < len) |
| { |
| if (index == pattern.length()) |
| index = 0; |
| |
| sb.append(pattern.charAt(index)); |
| index++; |
| numAdded++; |
| } |
| |
| return sb.toString(); |
| } |
| |
| /** |
| * See above |
| */ |
| public static String padding(double length) |
| { |
| return padding(length, " "); |
| } |
| |
| /** |
| * The str:split function splits up a string and returns a node set of token |
| * elements, each containing one token from the string. |
| * <p> |
| * The first argument is the string to be split. The second argument is a pattern |
| * string. The string given by the first argument is split at any occurrence of |
| * this pattern. For example: |
| * <pre> |
| * str:split('a, simple, list', ', ') gives the node set consisting of: |
| * |
| * <token>a</token> |
| * <token>simple</token> |
| * <token>list</token> |
| * </pre> |
| * If the second argument is omitted, the default is the string ' ' (i.e. a space). |
| * |
| * @param str The string to be split |
| * @param pattern The pattern |
| * |
| * @return A node set of split tokens |
| */ |
| public static NodeList split(String str, String pattern) |
| { |
| |
| |
| NodeSet resultSet = new NodeSet(); |
| resultSet.setShouldCacheNodes(true); |
| |
| boolean done = false; |
| int fromIndex = 0; |
| int matchIndex = 0; |
| String token = null; |
| |
| while (!done && fromIndex < str.length()) |
| { |
| matchIndex = str.indexOf(pattern, fromIndex); |
| if (matchIndex >= 0) |
| { |
| token = str.substring(fromIndex, matchIndex); |
| fromIndex = matchIndex + pattern.length(); |
| } |
| else |
| { |
| done = true; |
| token = str.substring(fromIndex); |
| } |
| |
| Document doc = DocumentHolder.m_doc; |
| synchronized (doc) |
| { |
| Element element = doc.createElement("token"); |
| Text text = doc.createTextNode(token); |
| element.appendChild(text); |
| resultSet.addNode(element); |
| } |
| } |
| |
| return resultSet; |
| } |
| |
| /** |
| * See above |
| */ |
| public static NodeList split(String str) |
| { |
| return split(str, " "); |
| } |
| |
| /** |
| * The str:tokenize function splits up a string and returns a node set of token |
| * elements, each containing one token from the string. |
| * <p> |
| * The first argument is the string to be tokenized. The second argument is a |
| * string consisting of a number of characters. Each character in this string is |
| * taken as a delimiting character. The string given by the first argument is split |
| * at any occurrence of any of these characters. For example: |
| * <pre> |
| * str:tokenize('2001-06-03T11:40:23', '-T:') gives the node set consisting of: |
| * |
| * <token>2001</token> |
| * <token>06</token> |
| * <token>03</token> |
| * <token>11</token> |
| * <token>40</token> |
| * <token>23</token> |
| * </pre> |
| * If the second argument is omitted, the default is the string '	

 ' |
| * (i.e. whitespace characters). |
| * <p> |
| * If the second argument is an empty string, the function returns a set of token |
| * elements, each of which holds a single character. |
| * <p> |
| * Note: This one is different from the tokenize extension function in the Xalan |
| * namespace. The one in Xalan returns a set of Text nodes, while this one wraps |
| * the Text nodes inside the token Element nodes. |
| * |
| * @param toTokenize The string to be tokenized |
| * @param delims The delimiter string |
| * |
| * @return A node set of split token elements |
| */ |
| public static NodeList tokenize(String toTokenize, String delims) |
| { |
| |
| |
| NodeSet resultSet = new NodeSet(); |
| |
| if (delims != null && delims.length() > 0) |
| { |
| StringTokenizer lTokenizer = new StringTokenizer(toTokenize, delims); |
| |
| Document doc = DocumentHolder.m_doc; |
| synchronized (doc) |
| { |
| while (lTokenizer.hasMoreTokens()) |
| { |
| Element element = doc.createElement("token"); |
| element.appendChild(doc.createTextNode(lTokenizer.nextToken())); |
| resultSet.addNode(element); |
| } |
| } |
| } |
| // If the delimiter is an empty string, create one token Element for |
| // every single character. |
| else |
| { |
| |
| Document doc = DocumentHolder.m_doc; |
| synchronized (doc) |
| { |
| for (int i = 0; i < toTokenize.length(); i++) |
| { |
| Element element = doc.createElement("token"); |
| element.appendChild(doc.createTextNode(toTokenize.substring(i, i+1))); |
| resultSet.addNode(element); |
| } |
| } |
| } |
| |
| return resultSet; |
| } |
| |
| /** |
| * See above |
| */ |
| public static NodeList tokenize(String toTokenize) |
| { |
| return tokenize(toTokenize, " \t\n\r"); |
| } |
| /** |
| * This class is not loaded until first referenced (see Java Language |
| * Specification by Gosling/Joy/Steele, section 12.4.1) |
| * |
| * The static members are created when this class is first referenced, as a |
| * lazy initialization not needing checking against null or any |
| * synchronization. |
| * |
| */ |
| private static class DocumentHolder |
| { |
| // Reuse the Document object to reduce memory usage. |
| private static final Document m_doc; |
| static { |
| try |
| { |
| m_doc =DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); |
| } |
| |
| catch(ParserConfigurationException pce) |
| { |
| throw new org.apache.xml.utils.WrappedRuntimeException(pce); |
| } |
| |
| } |
| } |
| |
| } |