View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.tobago.util;
21  
22  import org.w3c.dom.Document;
23  import org.w3c.dom.Element;
24  import org.w3c.dom.Node;
25  import org.w3c.dom.NodeList;
26  import org.xml.sax.EntityResolver;
27  import org.xml.sax.InputSource;
28  import org.xml.sax.SAXException;
29  
30  import javax.xml.parsers.DocumentBuilder;
31  import javax.xml.parsers.DocumentBuilderFactory;
32  import javax.xml.parsers.ParserConfigurationException;
33  import java.io.IOException;
34  import java.io.InputStream;
35  import java.io.StringReader;
36  import java.util.Properties;
37  
38  public final class XmlUtils {
39  
40    private XmlUtils() {
41    }
42  
43    public static String escape(final String s) {
44      return escape(s, true);
45    }
46  
47    public static String escape(final String s, final boolean isAttributeValue) {
48      if (null == s) {
49        return "";
50      }
51      final int len = s.length();
52      final StringBuilder buffer = new StringBuilder(len);
53      for (int i = 0; i < len; i++) {
54        appendEntityRef(buffer, s.charAt(i), isAttributeValue);
55      }
56      return buffer.toString();
57    }
58  
59    public static String escape(final char[] chars, final int offset, final int length, final boolean isAttributeValue) {
60      if (null == chars) {
61        return "";
62      }
63      final StringBuilder buffer = new StringBuilder(length);
64      for (int i = offset; i < length; i++) {
65        appendEntityRef(buffer, chars[i], isAttributeValue);
66      }
67      return buffer.toString();
68    }
69  
70    private static void appendEntityRef(final StringBuilder buffer, final char ch,
71        final boolean isAttributeValue) {
72      // Encode special XML characters into the equivalent character references.
73      // These five are defined by default for all XML documents.
74      switch (ch) {
75        case '<':
76          buffer.append("&lt;");
77          break;
78        case '&':
79          buffer.append("&amp;");
80          break;
81        case '"': // need inside attributes values
82          if (isAttributeValue) {
83            buffer.append("&quot;");
84          } else {
85            buffer.append(ch);
86          }
87          break;
88        case '\'': // need inside attributes values
89          if (isAttributeValue) {
90            buffer.append("&apos;");
91          } else {
92            buffer.append(ch);
93          }
94          break;
95        case '>': // optional
96          buffer.append("&gt;");
97          break;
98        default:
99          buffer.append(ch);
100     }
101   }
102 
103   /** @deprecated */
104   @Deprecated
105   public static void load(final Properties properties, final InputStream stream)
106       throws IOException {
107     final Document document;
108     try {
109       document = createDocument(stream);
110     } catch (final SAXException e) {
111       throw new RuntimeException("Invalid properties format", e);
112     }
113     final Element propertiesElement = (Element) document.getChildNodes().item(
114         document.getChildNodes().getLength() - 1);
115     importProperties(properties, propertiesElement);
116   }
117 
118   private static Document createDocument(final InputStream stream)
119       throws SAXException, IOException {
120     final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
121     factory.setIgnoringElementContentWhitespace(true);
122     factory.setValidating(false);
123     factory.setCoalescing(true);
124     factory.setIgnoringComments(true);
125     try {
126       final DocumentBuilder builder = factory.newDocumentBuilder();
127       builder.setEntityResolver(new Resolver());
128       final InputSource source = new InputSource(stream);
129       return builder.parse(source);
130     } catch (final ParserConfigurationException e) {
131       throw new Error(e);
132     }
133   }
134 
135   static void importProperties(final Properties properties, final Element propertiesElement) {
136     final NodeList entries = propertiesElement.getChildNodes();
137     final int numEntries = entries.getLength();
138     final int start = numEntries > 0
139         && entries.item(0).getNodeName().equals("comment") ? 1 : 0;
140     for (int i = start; i < numEntries; i++) {
141       final Node child = entries.item(i);
142       if (child instanceof Element) {
143         final Element entry = (Element) child;
144         if (entry.hasAttribute("key")) {
145           final Node node = entry.getFirstChild();
146           final String value = (node == null) ? "" : node.getNodeValue();
147           properties.setProperty(entry.getAttribute("key"), value);
148         }
149       }
150     }
151   }
152 
153   private static class Resolver implements EntityResolver {
154 
155     public InputSource resolveEntity(final String publicId, final String systemId)
156         throws SAXException {
157       final String dtd = "<!ELEMENT properties (comment?, entry*)>"
158           + "<!ATTLIST properties version CDATA #FIXED '1.0'>"
159           + "<!ELEMENT comment (#PCDATA)>"
160           + "<!ELEMENT entry (#PCDATA)>"
161           + "<!ATTLIST entry key CDATA #REQUIRED>";
162       final InputSource inputSource = new InputSource(new StringReader(dtd));
163       inputSource.setSystemId("http://java.sun.com/dtd/properties.dtd");
164       return inputSource;
165     }
166   }
167 
168 }