001 package org.apache.myfaces.tobago.util; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one or more 005 * contributor license agreements. See the NOTICE file distributed with 006 * this work for additional information regarding copyright ownership. 007 * The ASF licenses this file to You under the Apache License, Version 2.0 008 * (the "License"); you may not use this file except in compliance with 009 * the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019 020 import org.w3c.dom.Document; 021 import org.w3c.dom.Element; 022 import org.w3c.dom.Node; 023 import org.w3c.dom.NodeList; 024 import org.xml.sax.EntityResolver; 025 import org.xml.sax.InputSource; 026 import org.xml.sax.SAXException; 027 028 import javax.xml.parsers.DocumentBuilder; 029 import javax.xml.parsers.DocumentBuilderFactory; 030 import javax.xml.parsers.ParserConfigurationException; 031 import java.io.IOException; 032 import java.io.InputStream; 033 import java.io.StringReader; 034 import java.util.Properties; 035 036 public class XmlUtils { 037 038 public static String escape(String s) { 039 return escape(s, true); 040 } 041 042 public static String escape(String s, boolean isAttributeValue) { 043 if (null == s) { 044 return ""; 045 } 046 int len = s.length(); 047 StringBuilder buffer = new StringBuilder(len); 048 for (int i = 0; i < len; i++) { 049 appendEntityRef(buffer, s.charAt(i), isAttributeValue); 050 } 051 return buffer.toString(); 052 } 053 054 private static void appendEntityRef(StringBuilder buffer, char ch, 055 boolean isAttributeValue) { 056 // Encode special XML characters into the equivalent character references. 057 // These five are defined by default for all XML documents. 058 switch (ch) { 059 case '<': 060 buffer.append("<"); 061 break; 062 case '&': 063 buffer.append("&"); 064 break; 065 case '"': // need inside attributes values 066 if (isAttributeValue) { 067 buffer.append("""); 068 } else { 069 buffer.append(ch); 070 } 071 break; 072 case '\'': // need inside attributes values 073 if (isAttributeValue) { 074 buffer.append("'"); 075 } else { 076 buffer.append(ch); 077 } 078 break; 079 case '>': // optional 080 buffer.append(">"); 081 break; 082 default: 083 buffer.append(ch); 084 } 085 } 086 087 public static void load(Properties properties, InputStream stream) 088 throws IOException { 089 Document document; 090 try { 091 document = createDocument(stream); 092 } catch (SAXException e) { 093 throw new RuntimeException("Invalid properties format", e); 094 } 095 Element propertiesElement = (Element) document.getChildNodes().item( 096 document.getChildNodes().getLength() - 1); 097 importProperties(properties, propertiesElement); 098 } 099 100 private static Document createDocument(InputStream stream) 101 throws SAXException, IOException { 102 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 103 factory.setIgnoringElementContentWhitespace(true); 104 factory.setValidating(false); 105 factory.setCoalescing(true); 106 factory.setIgnoringComments(true); 107 try { 108 DocumentBuilder builder = factory.newDocumentBuilder(); 109 builder.setEntityResolver(new Resolver()); 110 InputSource source = new InputSource(stream); 111 return builder.parse(source); 112 } catch (ParserConfigurationException e) { 113 throw new Error(e); 114 } 115 } 116 117 static void importProperties(Properties properties, Element propertiesElement) { 118 NodeList entries = propertiesElement.getChildNodes(); 119 int numEntries = entries.getLength(); 120 int start = numEntries > 0 121 && entries.item(0).getNodeName().equals("comment") ? 1 : 0; 122 for (int i = start; i < numEntries; i++) { 123 Node child = entries.item(i); 124 if (child instanceof Element) { 125 Element entry = (Element) child; 126 if (entry.hasAttribute("key")) { 127 Node node = entry.getFirstChild(); 128 String value = (node == null) ? "" : node.getNodeValue(); 129 properties.setProperty(entry.getAttribute("key"), value); 130 } 131 } 132 } 133 } 134 135 private static class Resolver implements EntityResolver { 136 137 public InputSource resolveEntity(String publicId, String systemId) 138 throws SAXException { 139 String dtd = "<!ELEMENT properties (comment?, entry*)>" 140 + "<!ATTLIST properties version CDATA #FIXED '1.0'>" 141 + "<!ELEMENT comment (#PCDATA)>" 142 + "<!ELEMENT entry (#PCDATA)>" 143 + "<!ATTLIST entry key CDATA #REQUIRED>"; 144 InputSource inputSource = new InputSource(new StringReader(dtd)); 145 inputSource.setSystemId("http://java.sun.com/dtd/properties.dtd"); 146 return inputSource; 147 } 148 } 149 150 }