/*
* Copyright 2004-2015 the Seasar Foundation and the Others.
*
* 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.seasar.framework.xml;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import org.seasar.framework.util.ResourceUtil;
import org.seasar.framework.util.URLUtil;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
/**
* SAXのイベントを処理するためのクラスです。
*
* @author higa
*
*/
public class SaxHandler extends DefaultHandler {
private TagHandlerRule tagHandlerRule;
private TagHandlerContext context = new TagHandlerContext();
private Map dtdPaths = new HashMap();
private Locator locator;
/**
* {@link SaxHandler}を作成します。
*
* @param tagHandlerRule
*/
public SaxHandler(TagHandlerRule tagHandlerRule) {
this.tagHandlerRule = tagHandlerRule;
}
/**
* {@link TagHandlerContext}を返します。
*
* @return {@link TagHandlerContext}
*/
public TagHandlerContext getTagHandlerContext() {
return context;
}
public void setDocumentLocator(Locator locator) {
this.locator = locator;
}
public void startDocument() throws SAXException {
context.setLocator(locator);
}
public void startElement(String namespaceURI, String localName,
String qName, Attributes attributes) {
appendBody();
context.startElement(qName);
start(attributes);
}
public void characters(char[] buffer, int start, int length) {
int begin = start;
int end = start + length;
for (int i = begin; i < end; ++i) {
if (buffer[i] == '\n') {
context.characters(buffer, begin, i - begin + 1);
appendBody();
begin = i + 1;
}
}
if (begin < end) {
context.characters(buffer, begin, end - begin);
}
}
public void endElement(String namespaceURI, String localName, String qName) {
appendBody();
end();
context.endElement();
}
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException {
if (publicId != null) {
String dtdPath = (String) dtdPaths.get(publicId);
if (dtdPath != null) {
return createInputSource(ResourceUtil
.getResourceAsStream(dtdPath), systemId);
}
}
if (systemId == null) {
return null;
}
if (systemId.startsWith("file:")) {
URL url = URLUtil.create(systemId);
String path = url.getFile();
if (path.startsWith("/")) {
path = path.substring(1);
}
return createInputSource(ResourceUtil.getResourceAsStream(path),
systemId);
}
return new InputSource(ResourceUtil.getResourceAsStream(systemId));
}
public void error(SAXParseException e) throws SAXException {
throw e;
}
public void warning(SAXParseException e) throws SAXException {
System.err.println(e);
}
/**
* DTDの実際のパスを登録します。
*
* @param publicId
* @param dtdPath
*/
public void registerDtdPath(String publicId, String dtdPath) {
dtdPaths.put(publicId, dtdPath);
}
/**
* 処理された結果を返します。
*
* @return 処理された結果
*/
public Object getResult() {
return context.getResult();
}
private InputSource createInputSource(InputStream stream, String systemId) {
InputSource is = new InputSource(stream);
is.setSystemId(systemId);
return is;
}
private TagHandler getTagHandlerByPath() {
return tagHandlerRule.getTagHandler(context.getPath());
}
private TagHandler getTagHandlerByQName() {
return tagHandlerRule.getTagHandler(context.getQName());
}
private void start(Attributes attributes) {
TagHandler th = getTagHandlerByPath();
start(th, attributes);
th = getTagHandlerByQName();
start(th, attributes);
}
private void start(TagHandler handler, Attributes attributes) {
if (handler != null) {
try {
handler.start(context, attributes);
} catch (RuntimeException ex) {
reportDetailPath();
ex.printStackTrace();
throw ex;
}
}
}
private void appendBody() {
String characters = context.getCharacters();
if (characters.length() > 0) {
TagHandler th = getTagHandlerByPath();
appendBody(th, characters);
th = getTagHandlerByQName();
appendBody(th, characters);
context.clearCharacters();
}
}
private void appendBody(TagHandler handler, String characters) {
if (handler != null) {
try {
handler.appendBody(context, characters);
} catch (RuntimeException ex) {
reportDetailPath();
ex.printStackTrace();
throw ex;
}
}
}
private void end() {
String body = context.getBody();
TagHandler th = getTagHandlerByPath();
end(th, body);
th = getTagHandlerByQName();
end(th, body);
}
private void end(TagHandler handler, String body) {
if (handler != null) {
try {
handler.end(context, body);
} catch (RuntimeException ex) {
reportDetailPath();
ex.printStackTrace();
throw ex;
}
}
}
private void reportDetailPath() {
System.err.println("Exception occured at " + context.getDetailPath());
}
}