Java tutorial
/** * Copyright 2011 meltmedia * * Licensed 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. */ package org.xchain.framework.util; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.commons.jxpath.JXPathContext; import org.apache.commons.jxpath.JXPathException; import java.util.List; import java.util.ArrayList; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import java.util.regex.Matcher; import org.xchain.framework.jxpath.JXPathValidator; import javax.xml.namespace.NamespaceContext; /** * Utility class for Attribute related methods. * * @author Christian Trimble * @author Devon Tackett * @author Josh Kennedy * * @see org.xml.sax.Attributes */ public class AttributesUtil { private static Logger log = LoggerFactory.getLogger(AttributesUtil.class); /** A regex that matches the fixed part of an attribute value template. */ public static final String FIXED_PART_REGEX = "((?:[^{}]+|\\{\\{|\\}\\})+)"; /** A regex that matches the dynamic part of an attribute value template. */ public static final String DYNAMIC_PART_REGEX = "(?:\\{((?:[^\\}\'\"]*|\"[^\"]*\"|\'[^\']*\')*)\\})"; /** * The pattern for attribute value templates. The first group of this pattern is a fixed part, the second group is a dynamic part. This * pattern will match one part at a time. */ private static Pattern attributeValueTemplatePattern = null; static { try { attributeValueTemplatePattern = Pattern.compile(FIXED_PART_REGEX + "|" + DYNAMIC_PART_REGEX); } catch (PatternSyntaxException pse) { log.error("Could not compile attribute value template pattern.", pse); } } /** * Get the attribute value. * * @param attributes The list of attributes to check. * @param namespaceUri The namespace of the attribute. * @param localName The local name of the attribute. * * @return The value of the attribute if found. Null if not found. */ public static String getAttribute(Attributes attributes, String namespaceUri, String localName) { return getAttribute(attributes, namespaceUri, localName, null); } /** * Get the attribute value. * * @param attributes The list of attributes to check. * @param namespaceUri The namespace of the attribute. * @param localName The local name of the attribute. * @param defaultValue The default value to use if the attribute could not be found. * * @return The value of the attribute if found. The given defaultValue if not found. */ public static String getAttribute(Attributes attributes, String namespaceUri, String localName, String defaultValue) { String value = defaultValue; // get the index of the target attribute. int index = attributes.getIndex(namespaceUri, localName); // if the index is 0 or greater, then return the value. if (index >= 0) { value = attributes.getValue(index); } return value; } /** * Parses an attribute value template into fixed and dynamic parts. This list will always start with a fixed part and * then include alternating dynamic and fixed parts. */ public static List<String> parseAttributeValueTemplate(String attributeValueTemplate) throws SAXException { // the result. ArrayList<String> result = new ArrayList<String>(); // create the matcher. Matcher matcher = attributeValueTemplatePattern.matcher(attributeValueTemplate); while (matcher.lookingAt()) { String fixedPart = matcher.group(1); String dynamicPart = matcher.group(2); if (result.isEmpty() && fixedPart == null) { result.add(""); } if (fixedPart != null) { result.add(fixedPart.replaceAll("\\{\\{", "{").replaceAll("\\}\\}", "}")); } if (dynamicPart != null) { result.add(dynamicPart); } matcher.region(matcher.regionStart() + matcher.group().length(), matcher.regionEnd()); } if (!matcher.hitEnd()) { throw new SAXException( "The attribute value template '" + attributeValueTemplate + "' has an error between characters " + matcher.regionStart() + " and " + matcher.regionEnd() + "."); } return result; } /** * Evaluates an attribute value template using the provided JXPathContext object. */ public static String evaluateAttributeValueTemplate(JXPathContext context, String attributeValueTemplate) throws SAXException, Exception { List<String> parsedAvt = parseAttributeValueTemplate(attributeValueTemplate); // if there is just one part, then return the string. if (parsedAvt.size() == 1) { return parsedAvt.get(0); } // build a string buffer and start building the result in it. StringBuilder sb = new StringBuilder(); for (int i = 0; i < parsedAvt.size(); i += 2) { sb.append(parsedAvt.get(i)); if ((i + 1) < parsedAvt.size()) { sb.append((String) context.getValue(parsedAvt.get(i + 1), String.class)); } } return sb.toString(); } public static void validateAttributeValueTemplate(String attributeValueTemplate, NamespaceContext namespaceContext) throws JXPathException { List<String> parsedAvt = null; try { parsedAvt = parseAttributeValueTemplate(attributeValueTemplate); } catch (SAXException saxe) { throw new JXPathException(saxe.getMessage()); } // validate the xpaths nested in the attribute value template. for (int i = 1; i < parsedAvt.size(); i += 2) { JXPathValidator.validate(parsedAvt.get(i), namespaceContext); } } }