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;
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<>();
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を返す。
81 * @param base 絶対URIでなければならない。nullでもよい。
82 * @param relative 絶対URIでもよいがその場合baseは無視される。null可。
83 * @return 合成結果のURLオブジェクト。必ず絶対URIになる。
84 * @throws java.net.URISyntaxException URIとして変。
85 * @throws java.lang.IllegalArgumentException 絶対URIが生成できない。
87 protected static URI buildBaseRelativeURI(String base, String relative)
88 throws URISyntaxException,
89 IllegalArgumentException {
92 baseURI = new URI(base);
93 if( ! baseURI.isAbsolute() ){
94 throw new IllegalArgumentException();
101 if(relative != null){
102 relativeURI = new URI(relative);
104 relativeURI = EMPTY_URI;
107 URI result = buildBaseRelativeURI(baseURI, relativeURI);
112 * 絶対URIと相対URIを合成したURIを返す。
115 * @param baseURI 絶対URIでなければならない。nullでもよい。
116 * @param relativeURI 絶対URIでもよいがその場合baseは無視される。
117 * @return 合成結果のURLオブジェクト。必ず絶対URIになる。
118 * @throws java.lang.IllegalArgumentException 絶対URIが生成できない。
120 private static URI buildBaseRelativeURI(URI baseURI, URI relativeURI)
121 throws IllegalArgumentException {
124 if(baseURI == null || relativeURI.isAbsolute()){
125 resultURI = relativeURI;
127 resultURI = baseURI.resolve(relativeURI);
130 if( ! resultURI.isAbsolute() ){
131 throw new IllegalArgumentException();
134 resultURI = resultURI.normalize();
143 public static LSInput createLSInput(){
144 LSInput input = new LSInputImpl();
150 * オリジナルURIとリダイレクト先のURIを登録する。
151 * オリジナルURIへのアクセスはリダイレクトされる。
152 * @param original オリジナルURI
153 * @param redirect リダイレクトURI
155 private void putRedirectedImpl(URI original, URI redirect){
156 URI oridinalNorm = original.normalize();
157 URI redirectNorm = redirect.normalize();
159 this.uriMap.put(oridinalNorm, redirectNorm);
165 * オリジナルURIとリダイレクト先のURIを登録する。
166 * オリジナルURIへのアクセスはリダイレクトされる。
167 * @param original オリジナルURI
168 * @param redirect リダイレクトURI
170 public void putRedirected(URI original, URI redirect){
171 putRedirectedImpl(original, redirect);
176 * ローカル版リソース参照解決を登録する。
177 * @param lsc ローカル版リソース参照解決
179 public void putRedirected(LocalXmlResource lsc){
180 URI original = lsc.getOriginalResource();
181 if(original == null) return;
183 URI local = lsc.getLocalResource();
185 putRedirected(original, local);
194 public void putRedirected(XmlResourceResolver other){
195 this.uriMap.putAll(other.uriMap);
201 * @param original オリジナルURI
202 * @return リダイレクト先URI。未登録の場合はnull
204 public URI getRedirected(URI original){
205 URI keyURI = original.normalize();
206 URI resourceURI = this.uriMap.get(keyURI);
212 * @param original オリジナルURI
213 * @return リダイレクト先URI。未登録の場合はオリジナルを返す
215 public URI resolveRedirected(URI original){
216 URI result = getRedirected(original);
217 if(result == null) result = original;
222 * 登録済みリダイレクト先リソースの入力ストリームを得る。
223 * @param originalURI オリジナルURI
224 * @return 入力ストリーム。リダイレクト先が未登録の場合はnull
225 * @throws java.io.IOException 入出力エラー。
228 private InputStream getXMLResourceAsStream(URI originalURI)
230 URI resourceURI = getRedirected(originalURI);
231 if(resourceURI == null) return null;
233 URL resourceURL = resourceURI.toURL();
234 InputStream is = resourceURL.openStream();
241 * URL変換したあとの入力ソースを返す。
242 * @param type {@inheritDoc}
243 * @param namespaceURI {@inheritDoc}
244 * @param publicId {@inheritDoc}
245 * @param systemId {@inheritDoc}
246 * @param baseURI {@inheritDoc}
247 * @return {@inheritDoc}
250 public LSInput resolveResource(String type,
255 if(systemId == null) return null;
259 originalURI = buildBaseRelativeURI(baseURI, systemId);
260 }catch(URISyntaxException e){
266 is = getXMLResourceAsStream(originalURI);
267 }catch(IOException e){
270 if(is == null) return null;
272 LSInput input = createLSInput();
273 input.setBaseURI(baseURI);
274 input.setPublicId(publicId);
275 input.setSystemId(systemId);
276 input.setByteStream(is);
283 * URL変換したあとの入力ソースを返す。
284 * @param publicId {@inheritDoc}
285 * @param systemId {@inheritDoc}
286 * @return {@inheritDoc}
287 * @throws org.xml.sax.SAXException {@inheritDoc}
288 * @throws java.io.IOException {@inheritDoc}
291 public InputSource resolveEntity(String publicId, String systemId)
292 throws SAXException, IOException{
293 if(systemId == null) return null;
297 originalUri = new URI(systemId);
298 }catch(URISyntaxException e){
302 InputStream is = getXMLResourceAsStream(originalUri);
303 if(is == null) return null;
305 InputSource source = new InputSource(is);
306 source.setPublicId(publicId);
307 source.setSystemId(systemId);
315 * org.w3c.dom.ls.DOMImplementationLS#createLSInput()
318 private static final class LSInputImpl implements LSInput {
320 private String baseURI = null;
321 private InputStream byteStream = null;
322 private boolean certifiedText = false;
323 private Reader characterStream = null;
324 private String encoding = null;
325 private String publicId = null;
326 private String stringData = null;
327 private String systemId = null;
339 * @return {@inheritDoc}
342 public String getBaseURI(){
348 * @param baseURI {@inheritDoc}
351 public void setBaseURI(String baseURI){
352 this.baseURI = baseURI;
358 * @return {@inheritDoc}
361 public InputStream getByteStream(){
362 return this.byteStream;
367 * @param byteStream {@inheritDoc}
370 public void setByteStream(InputStream byteStream){
371 this.byteStream = byteStream;
376 * @return {@inheritDoc}
379 public boolean getCertifiedText(){
380 return this.certifiedText;
385 * @param certifiedText {@inheritDoc}
388 public void setCertifiedText(boolean certifiedText){
389 this.certifiedText = certifiedText;
395 * @return {@inheritDoc}
398 public Reader getCharacterStream(){
399 return this.characterStream;
404 * @param characterStream {@inheritDoc}
407 public void setCharacterStream(Reader characterStream){
408 this.characterStream = characterStream;
413 * @return {@inheritDoc}
416 public String getEncoding(){
417 return this.encoding;
422 * @param encoding {@inheritDoc}
425 public void setEncoding(String encoding){
426 this.encoding = encoding;
432 * @return {@inheritDoc}
435 public String getPublicId(){
436 return this.publicId;
441 * @param publicId {@inheritDoc}
444 public void setPublicId(String publicId){
445 this.publicId = publicId;
451 * @return {@inheritDoc}
454 public String getStringData(){
455 return this.stringData;
460 * @param stringData {@inheritDoc}
463 public void setStringData(String stringData){
464 this.stringData = stringData;
470 * @return {@inheritDoc}
473 public String getSystemId(){
474 return this.systemId;
479 * @param systemId {@inheritDoc}
482 public void setSystemId(String systemId){
483 this.systemId = systemId;