2 * xml resource resolver
4 * License : The MIT License
5 * Copyright(c) 2009 olyutorskii
8 package jp.sfjp.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;
23 * URL変換マップに従い、XML文書からの外部参照をリダイレクトする。
24 * 相対URIはこのクラスをベースに解決される。
25 * 主な用途は外部スキーマのリソース化など。
27 public class XmlResourceResolver
28 implements LSResourceResolver{
31 public static final String SCHEMA_XML =
32 "http://www.w3.org/2001/xml.xsd";
35 public static final String NS_XSD =
36 "http://www.w3.org/2001/XMLSchema-instance";
38 private static final String LOCAL_SCHEMA_XML =
39 "resources/xmlspace.xsd";
41 private static final URI EMPTY_URI = URI.create("");
43 private static final Class<?> THISCLASS = XmlResourceResolver.class;
46 private final Map<URI, URI> uriMap;
52 public XmlResourceResolver(){
55 assert this.getClass().equals(THISCLASS);
58 map = new HashMap<>();
59 map = Collections.synchronizedMap(map);
62 URL redirectRes = THISCLASS.getResource(LOCAL_SCHEMA_XML);
63 String redirectResName = redirectRes.toString();
65 URI originalURI = URI.create(SCHEMA_XML);
66 URI redirectURI = URI.create(redirectResName);
68 putRedirectedImpl(originalURI, redirectURI);
75 * 絶対URIと相対URIを合成したURIを返す。
78 * @param base 絶対URIでなければならない。nullでもよい。
79 * @param relative 絶対URIでもよいがその場合baseは無視される。null可。
80 * @return 合成結果のURLオブジェクト。必ず絶対URIになる。
81 * @throws java.net.URISyntaxException URIとして変。
82 * @throws java.lang.IllegalArgumentException 絶対URIが生成できない。
84 protected static URI buildBaseRelativeURI(String base, String relative)
85 throws URISyntaxException,
86 IllegalArgumentException {
89 baseURI = new URI(base);
90 if( ! baseURI.isAbsolute() ){
91 throw new IllegalArgumentException();
99 relativeURI = new URI(relative);
101 relativeURI = EMPTY_URI;
104 URI result = buildBaseRelativeURI(baseURI, relativeURI);
109 * 絶対URIと相対URIを合成したURIを返す。
112 * @param baseURI 絶対URIでなければならない。nullでもよい。
113 * @param relativeURI 絶対URIでもよいがその場合baseは無視される。
114 * @return 合成結果のURLオブジェクト。必ず絶対URIになる。
115 * @throws java.lang.IllegalArgumentException 絶対URIが生成できない。
117 private static URI buildBaseRelativeURI(URI baseURI, URI relativeURI)
118 throws IllegalArgumentException {
121 if(baseURI == null || relativeURI.isAbsolute()){
122 resultURI = relativeURI;
124 resultURI = baseURI.resolve(relativeURI);
127 if( ! resultURI.isAbsolute() ){
128 throw new IllegalArgumentException();
131 resultURI = resultURI.normalize();
140 public static LSInput createLSInput(){
141 LSInput input = new LSInputImpl();
147 * オリジナルURIとリダイレクト先のURIを登録する。
148 * オリジナルURIへのアクセスはリダイレクトされる。
149 * @param original オリジナルURI
150 * @param redirect リダイレクトURI
152 private void putRedirectedImpl(URI original, URI redirect){
153 URI oridinalNorm = original.normalize();
154 URI redirectNorm = redirect.normalize();
156 this.uriMap.put(oridinalNorm, redirectNorm);
162 * オリジナルURIとリダイレクト先のURIを登録する。
163 * オリジナルURIへのアクセスはリダイレクトされる。
164 * @param original オリジナルURI
165 * @param redirect リダイレクトURI
167 public void putRedirected(URI original, URI redirect){
168 putRedirectedImpl(original, redirect);
173 * ローカル版リソース参照解決を登録する。
174 * @param lsc ローカル版リソース参照解決
176 public void putRedirected(LocalXmlResource lsc){
177 URI original = lsc.getOriginalResource();
178 if(original == null) return;
180 URI local = lsc.getLocalResource();
182 putRedirected(original, local);
191 public void putRedirected(XmlResourceResolver other){
192 this.uriMap.putAll(other.uriMap);
198 * @param original オリジナルURI
199 * @return リダイレクト先URI。未登録の場合はnull
201 public URI getRedirected(URI original){
202 URI keyURI = original.normalize();
203 URI resourceURI = this.uriMap.get(keyURI);
209 * @param original オリジナルURI
210 * @return リダイレクト先URI。未登録の場合はオリジナルを返す
212 public URI resolveRedirected(URI original){
213 URI result = getRedirected(original);
214 if(result == null) result = original;
219 * 登録済みリダイレクト先リソースの入力ストリームを得る。
220 * @param originalURI オリジナルURI
221 * @return 入力ストリーム。リダイレクト先が未登録の場合はnull
222 * @throws java.io.IOException 入出力エラー。
225 private InputStream getXMLResourceAsStream(URI originalURI)
227 URI resourceURI = getRedirected(originalURI);
228 if(resourceURI == null) return null;
230 URL resourceURL = resourceURI.toURL();
231 InputStream is = resourceURL.openStream();
238 * URL変換したあとの入力ソースを返す。
239 * @param type {@inheritDoc}
240 * @param namespaceURI {@inheritDoc}
241 * @param publicId {@inheritDoc}
242 * @param systemId {@inheritDoc}
243 * @param baseURI {@inheritDoc}
244 * @return {@inheritDoc}
247 public LSInput resolveResource(String type,
252 if(systemId == null) return null;
256 originalURI = buildBaseRelativeURI(baseURI, systemId);
257 }catch(URISyntaxException e){
263 is = getXMLResourceAsStream(originalURI);
264 }catch(IOException e){
267 if(is == null) return null;
269 LSInput input = createLSInput();
270 input.setBaseURI(baseURI);
271 input.setPublicId(publicId);
272 input.setSystemId(systemId);
273 input.setByteStream(is);
282 * org.w3c.dom.ls.DOMImplementationLS#createLSInput()
285 private static final class LSInputImpl implements LSInput {
287 private String baseURI = null;
288 private InputStream byteStream = null;
289 private boolean certifiedText = false;
290 private Reader characterStream = null;
291 private String encoding = null;
292 private String publicId = null;
293 private String stringData = null;
294 private String systemId = null;
306 * @return {@inheritDoc}
309 public String getBaseURI(){
315 * @param baseURI {@inheritDoc}
318 public void setBaseURI(String baseURI){
319 this.baseURI = baseURI;
325 * @return {@inheritDoc}
328 public InputStream getByteStream(){
329 return this.byteStream;
334 * @param byteStream {@inheritDoc}
337 public void setByteStream(InputStream byteStream){
338 this.byteStream = byteStream;
343 * @return {@inheritDoc}
346 public boolean getCertifiedText(){
347 return this.certifiedText;
352 * @param certifiedText {@inheritDoc}
355 public void setCertifiedText(boolean certifiedText){
356 this.certifiedText = certifiedText;
362 * @return {@inheritDoc}
365 public Reader getCharacterStream(){
366 return this.characterStream;
371 * @param characterStream {@inheritDoc}
374 public void setCharacterStream(Reader characterStream){
375 this.characterStream = characterStream;
380 * @return {@inheritDoc}
383 public String getEncoding(){
384 return this.encoding;
389 * @param encoding {@inheritDoc}
392 public void setEncoding(String encoding){
393 this.encoding = encoding;
399 * @return {@inheritDoc}
402 public String getPublicId(){
403 return this.publicId;
408 * @param publicId {@inheritDoc}
411 public void setPublicId(String publicId){
412 this.publicId = publicId;
418 * @return {@inheritDoc}
421 public String getStringData(){
422 return this.stringData;
427 * @param stringData {@inheritDoc}
430 public void setStringData(String stringData){
431 this.stringData = stringData;
437 * @return {@inheritDoc}
440 public String getSystemId(){
441 return this.systemId;
446 * @param systemId {@inheritDoc}
449 public void setSystemId(String systemId){
450 this.systemId = systemId;