001: /*
002: * Copyright 2004 Outerthought bvba and Schaubroeck nv
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.outerj.daisy.books.publisher.impl.util;
017:
018: import org.xml.sax.helpers.DefaultHandler;
019: import org.xml.sax.helpers.AttributesImpl;
020: import org.xml.sax.Attributes;
021: import org.xml.sax.SAXException;
022: import org.xml.sax.InputSource;
023: import org.xml.sax.ContentHandler;
024: import org.outerj.daisy.xmlutil.LocalSAXParserFactory;
025:
026: import javax.xml.parsers.SAXParser;
027: import java.util.Map;
028: import java.util.LinkedHashMap;
029: import java.io.InputStream;
030:
031: /**
032: * Reads properties from a Java 1.5 style XML properties file.
033: */
034: public class XMLPropertiesHelper {
035:
036: public static Map<String, String> load(InputStream is)
037: throws Exception {
038: return load(is, (Map<String, String>) null);
039: }
040:
041: public static Map<String, String> load(InputStream is,
042: Map<String, String> defaults) throws Exception {
043: return load(is, defaults, "properties");
044: }
045:
046: public static Map<String, String> load(InputStream is,
047: String rootElement) throws Exception {
048: return load(is, null, rootElement);
049: }
050:
051: public static Map<String, String> load(InputStream is,
052: Map<String, String> defaults, String rootElement)
053: throws Exception {
054: return load(new InputSource(is), defaults, rootElement);
055: }
056:
057: public static Map<String, String> load(InputSource is,
058: Map<String, String> defaults, String rootElement)
059: throws Exception {
060: SAXParser parser = LocalSAXParserFactory.getSAXParserFactory()
061: .newSAXParser();
062: // A LinkedHashMap is used because we want to maintain the order of the properties
063: // (the properties are displayed to the user, having them displayed in random order would not be nice)
064: Map<String, String> properties = new LinkedHashMap<String, String>();
065: if (defaults != null)
066: properties.putAll(defaults);
067: PropertiesHandler propertiesHandler = new PropertiesHandler(
068: properties, rootElement);
069: parser.getXMLReader().setContentHandler(propertiesHandler);
070: parser.getXMLReader().parse(is);
071: return properties;
072: }
073:
074: public static void generateSaxFragment(Map<String, String> map,
075: ContentHandler contentHandler) throws SAXException {
076: generateSaxFragment(map, "properties", contentHandler);
077: }
078:
079: public static void generateSaxFragment(Map<String, String> map,
080: String rootElement, ContentHandler contentHandler)
081: throws SAXException {
082: contentHandler.startElement("", rootElement, rootElement,
083: new AttributesImpl());
084:
085: for (Map.Entry<String, String> entry : map.entrySet()) {
086: String key = entry.getKey();
087: String value = entry.getValue();
088: AttributesImpl attrs = new AttributesImpl();
089: attrs.addAttribute("", "key", "key", "CDATA", key);
090: contentHandler.startElement("", "entry", "entry", attrs);
091: contentHandler.characters(value.toCharArray(), 0, value
092: .length());
093: contentHandler.endElement("", "entry", "entry");
094: }
095:
096: contentHandler.endElement("", rootElement, rootElement);
097: }
098:
099: private static class PropertiesHandler extends DefaultHandler {
100: private String rootElementName;
101: private final Map<String, String> properties;
102: private int nesting = 0;
103: private String key = null;
104: private StringBuilder entry = new StringBuilder();
105:
106: public PropertiesHandler(Map<String, String> properties,
107: String rootElementName) {
108: this .rootElementName = rootElementName;
109: this .properties = properties;
110: }
111:
112: public void startElement(String uri, String localName,
113: String qName, Attributes attributes)
114: throws SAXException {
115: nesting++;
116: if (nesting == 1
117: && !(uri.equals("") && localName
118: .equals(rootElementName))) {
119: throw new SAXException("Expected <" + rootElementName
120: + "> root element.");
121: } else if (nesting == 2 && uri.equals("")
122: && localName.equals("entry")) {
123: entry.setLength(0);
124: key = attributes.getValue("key");
125: if (key == null || key.trim().equals("")) {
126: throw new SAXException(
127: "Missing or empty key attribute on <entry> element.");
128: }
129: }
130: }
131:
132: public void endElement(String uri, String localName,
133: String qName) throws SAXException {
134: if (nesting == 2 && key != null) {
135: properties.put(key, entry.toString());
136: key = null;
137: }
138: nesting--;
139: }
140:
141: public void characters(char ch[], int start, int length)
142: throws SAXException {
143: if (key != null)
144: entry.append(ch, start, length);
145: }
146: }
147: }
|