2 * xml resource resolver
4 * License : The MIT License
5 * Copyright(c) 2009 olyutorskii
8 package jp.sourceforge.mikutoga.xml;
10 import java.io.IOException;
11 import java.io.InputStream;
12 import java.io.Reader;
14 import java.net.URISyntaxException;
16 import java.util.Collections;
17 import java.util.HashMap;
19 import org.w3c.dom.ls.LSInput;
20 import org.w3c.dom.ls.LSResourceResolver;
21 import org.xml.sax.EntityResolver;
22 import org.xml.sax.InputSource;
23 import org.xml.sax.SAXException;
26 * URL変換マップに従い、XML文書からの外部参照をリダイレクトする。
27 * 相対URIはこのクラスをベースに解決される。
28 * 主な用途は外部スキーマのリソース化など。
30 public class XmlResourceResolver
31 implements LSResourceResolver, EntityResolver {
34 public static final String SCHEMA_XML =
35 "http://www.w3.org/2001/xml.xsd";
38 public static final String NS_XSD =
39 "http://www.w3.org/2001/XMLSchema-instance";
41 private static final String LOCAL_SCHEMA_XML =
42 "resources/xmlspace.xsd";
44 private static final URI EMPTY_URI = URI.create("");
46 private static final Class<?> THISCLASS = XmlResourceResolver.class;
49 private final Map<URI, URI> uriMap;
55 public XmlResourceResolver(){
58 assert this.getClass().equals(THISCLASS);
61 map = new HashMap<URI, URI>();
62 map = Collections.synchronizedMap(map);
65 URL redirectRes = THISCLASS.getResource(LOCAL_SCHEMA_XML);
66 String redirectResName = redirectRes.toString();
68 URI originalURI = URI.create(SCHEMA_XML);
69 URI redirectURI = URI.create(redirectResName);
71 putRedirectedImpl(originalURI, redirectURI);
78 * 絶対URIと相対URIを合成したURIを返す。
80 * @param base 絶対URIでなければならない。nullでもよい。
81 * @param relative 絶対URIでもよいがその場合baseは無視される。null可。
82 * @return 合成結果のURLオブジェクト。必ず絶対URIになる。
83 * @throws java.net.URISyntaxException URIとして変。
84 * @throws java.lang.IllegalArgumentException 絶対URIが生成できない。
86 protected static URI buildBaseRelativeURI(String base, String relative)
87 throws URISyntaxException,
88 IllegalArgumentException {
91 baseURI = new URI(base);
92 if( ! baseURI.isAbsolute() ){
93 throw new IllegalArgumentException();
100 if(relative != null){
101 relativeURI = new URI(relative);
103 relativeURI = EMPTY_URI;
107 if(baseURI == null || relativeURI.isAbsolute()){
108 resultURI = relativeURI;
110 resultURI = baseURI.resolve(relativeURI);
113 if( ! resultURI.isAbsolute() ){
114 throw new IllegalArgumentException();
117 resultURI = resultURI.normalize();
126 public static LSInput createLSInput(){
127 LSInput input = new LSInputImpl();
133 * オリジナルURIとリダイレクト先のURIを登録する。
134 * オリジナルURIへのアクセスはリダイレクトされる。
135 * @param original オリジナルURI
136 * @param redirect リダイレクトURI
138 private void putRedirectedImpl(URI original, URI redirect){
139 URI oridinalNorm = original.normalize();
140 URI redirectNorm = redirect.normalize();
142 this.uriMap.put(oridinalNorm, redirectNorm);
148 * オリジナルURIとリダイレクト先のURIを登録する。
149 * オリジナルURIへのアクセスはリダイレクトされる。
150 * @param original オリジナルURI
151 * @param redirect リダイレクトURI
153 public void putRedirected(URI original, URI redirect){
154 putRedirectedImpl(original, redirect);
159 * ローカル版リソース参照解決を登録する。
160 * @param lsc ローカル版リソース参照解決
162 public void putRedirected(LocalXmlResource lsc){
163 URI original = lsc.getOriginalResource();
164 if(original == null) return;
166 URI local = lsc.getLocalResource();
168 putRedirected(original, local);
177 public void putRedirected(XmlResourceResolver other){
178 this.uriMap.putAll(other.uriMap);
184 * @param original オリジナルURI
185 * @return リダイレクト先URI。未登録の場合はnull
187 public URI getRedirected(URI original){
188 URI keyURI = original.normalize();
189 URI resourceURI = this.uriMap.get(keyURI);
195 * @param original オリジナルURI
196 * @return リダイレクト先URI。未登録の場合はオリジナルを返す
198 public URI resolveRedirected(URI original){
199 URI result = getRedirected(original);
200 if(result == null) result = original;
205 * 登録済みリダイレクト先リソースの入力ストリームを得る。
206 * @param originalURI オリジナルURI
207 * @return 入力ストリーム。リダイレクト先が未登録の場合はnull
208 * @throws java.io.IOException 入出力エラー。
211 private InputStream getXMLResourceAsStream(URI originalURI)
213 URI resourceURI = getRedirected(originalURI);
214 if(resourceURI == null) return null;
216 URL resourceURL = resourceURI.toURL();
217 InputStream is = resourceURL.openStream();
224 * URL変換したあとの入力ソースを返す。
225 * @param type {@inheritDoc}
226 * @param namespaceURI {@inheritDoc}
227 * @param publicId {@inheritDoc}
228 * @param systemId {@inheritDoc}
229 * @param baseURI {@inheritDoc}
230 * @return {@inheritDoc}
233 public LSInput resolveResource(String type,
238 if(systemId == null) return null;
242 originalURI = buildBaseRelativeURI(baseURI, systemId);
243 }catch(URISyntaxException e){
249 is = getXMLResourceAsStream(originalURI);
250 }catch(IOException e){
253 if(is == null) return null;
255 LSInput input = createLSInput();
256 input.setBaseURI(baseURI);
257 input.setPublicId(publicId);
258 input.setSystemId(systemId);
259 input.setByteStream(is);
266 * URL変換したあとの入力ソースを返す。
267 * @param publicId {@inheritDoc}
268 * @param systemId {@inheritDoc}
269 * @return {@inheritDoc}
270 * @throws org.xml.sax.SAXException {@inheritDoc}
271 * @throws java.io.IOException {@inheritDoc}
274 public InputSource resolveEntity(String publicId, String systemId)
275 throws SAXException, IOException{
276 if(systemId == null) return null;
280 originalUri = new URI(systemId);
281 }catch(URISyntaxException e){
285 InputStream is = getXMLResourceAsStream(originalUri);
286 if(is == null) return null;
288 InputSource source = new InputSource(is);
289 source.setPublicId(publicId);
290 source.setSystemId(systemId);
298 * org.w3c.dom.ls.DOMImplementationLS#createLSInput()
301 private static final class LSInputImpl implements LSInput {
303 private String baseURI = null;
304 private InputStream byteStream = null;
305 private boolean certifiedText = false;
306 private Reader characterStream = null;
307 private String encoding = null;
308 private String publicId = null;
309 private String stringData = null;
310 private String systemId = null;
322 * @return {@inheritDoc}
325 public String getBaseURI(){
331 * @param baseURI {@inheritDoc}
334 public void setBaseURI(String baseURI){
335 this.baseURI = baseURI;
341 * @return {@inheritDoc}
344 public InputStream getByteStream(){
345 return this.byteStream;
350 * @param byteStream {@inheritDoc}
353 public void setByteStream(InputStream byteStream){
354 this.byteStream = byteStream;
359 * @return {@inheritDoc}
362 public boolean getCertifiedText(){
363 return this.certifiedText;
368 * @param certifiedText {@inheritDoc}
371 public void setCertifiedText(boolean certifiedText){
372 this.certifiedText = certifiedText;
378 * @return {@inheritDoc}
381 public Reader getCharacterStream(){
382 return this.characterStream;
387 * @param characterStream {@inheritDoc}
390 public void setCharacterStream(Reader characterStream){
391 this.characterStream = characterStream;
396 * @return {@inheritDoc}
399 public String getEncoding(){
400 return this.encoding;
405 * @param encoding {@inheritDoc}
408 public void setEncoding(String encoding){
409 this.encoding = encoding;
415 * @return {@inheritDoc}
418 public String getPublicId(){
419 return this.publicId;
424 * @param publicId {@inheritDoc}
427 public void setPublicId(String publicId){
428 this.publicId = publicId;
434 * @return {@inheritDoc}
437 public String getStringData(){
438 return this.stringData;
443 * @param stringData {@inheritDoc}
446 public void setStringData(String stringData){
447 this.stringData = stringData;
453 * @return {@inheritDoc}
456 public String getSystemId(){
457 return this.systemId;
462 * @param systemId {@inheritDoc}
465 public void setSystemId(String systemId){
466 this.systemId = systemId;