Mega Code Archive

 
Categories / Java / XML
 

Resolve relative URIs and SystemID strings into absolute URIs

/*  * Licensed to the Apache Software Foundation (ASF) under one  * or more contributor license agreements. See the NOTICE file  * distributed with this work for additional information  * regarding copyright ownership. The ASF licenses this file  * to you 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.  */ /*  * $Id: SystemIDResolver.java 468655 2006-10-28 07:12:06Z minchau $  */ import java.io.File; import java.net.URI; import javax.xml.transform.TransformerException; /**  * This class is used to resolve relative URIs and SystemID   * strings into absolute URIs.  *  * <p>This is a generic utility for resolving URIs, other than the   * fact that it's declared to throw TransformerException.  Please   * see code comments for details on how resolution is performed.</p>  * @xsl.usage internal  */ public class SystemIDResolver {   /**    * Get an absolute URI from a given relative URI (local path).     *     * <p>The relative URI is a local filesystem path. The path can be    * absolute or relative. If it is a relative path, it is resolved relative     * to the system property "user.dir" if it is available; if not (i.e. in an     * Applet perhaps which throws SecurityException) then we just return the    * relative path. The space and backslash characters are also replaced to    * generate a good absolute URI.</p>    *    * @param localPath The relative URI to resolve    *    * @return Resolved absolute URI    */   public static String getAbsoluteURIFromRelative(String localPath)   {     if (localPath == null || localPath.length() == 0)       return "";            // If the local path is a relative path, then it is resolved against     // the "user.dir" system property.     String absolutePath = localPath;     if (!isAbsolutePath(localPath))     {       try        {         absolutePath = getAbsolutePathFromRelativePath(localPath);       }       // user.dir not accessible from applet       catch (SecurityException se)        {         return "file:" + localPath;       }     }     String urlString;     if (null != absolutePath)     {       if (absolutePath.startsWith(File.separator))         urlString = "file://" + absolutePath;       else         urlString = "file:///" + absolutePath;             }     else       urlString = "file:" + localPath;          return replaceChars(urlString);   }      /**    * Return an absolute path from a relative path.    *    * @param relativePath A relative path    * @return The absolute path    */   private static String getAbsolutePathFromRelativePath(String relativePath)   {     return new File(relativePath).getAbsolutePath();   }      /**    * Return true if the systemId denotes an absolute URI .    *    * @param systemId The systemId string    * @return true if the systemId is an an absolute URI    */   public static boolean isAbsoluteURI(String systemId)   {      /** http://www.ietf.org/rfc/rfc2396.txt       *   Authors should be aware that a path segment which contains a colon       * character cannot be used as the first segment of a relative URI path       * (e.g., "this:that"), because it would be mistaken for a scheme name.      **/      /**        * %REVIEW% Can we assume here that systemId is a valid URI?       * It looks like we cannot ( See discussion of this common problem in        * Bugzilla Bug 22777 ).       **/      //"fix" for Bugzilla Bug 22777     if(isWindowsAbsolutePath(systemId)){         return false;      }          final int fragmentIndex = systemId.indexOf('#');     final int queryIndex = systemId.indexOf('?');     final int slashIndex = systemId.indexOf('/');     final int colonIndex = systemId.indexOf(':');          //finding substring  before '#', '?', and '/'      int index = systemId.length() -1;     if(fragmentIndex > 0)          index = fragmentIndex;     if((queryIndex > 0) && (queryIndex <index))          index = queryIndex;     if((slashIndex > 0) && (slashIndex <index))         index = slashIndex;      // return true if there is ':' before '#', '?', and '/'     return ((colonIndex >0) && (colonIndex<index));        }      /**    * Return true if the local path is an absolute path.    *    * @param systemId The path string    * @return true if the path is absolute    */   public static boolean isAbsolutePath(String systemId)   {     if(systemId == null)         return false;     final File file = new File(systemId);     return file.isAbsolute();        }       /**    * Return true if the local path is a Windows absolute path.    *    * @param systemId The path string    * @return true if the path is a Windows absolute path    */     private static boolean isWindowsAbsolutePath(String systemId)   {     if(!isAbsolutePath(systemId))       return false;     // On Windows, an absolute path starts with "[drive_letter]:\".     if (systemId.length() > 2          && systemId.charAt(1) == ':'         && Character.isLetter(systemId.charAt(0))         && (systemId.charAt(2) == '\\' || systemId.charAt(2) == '/'))       return true;     else       return false;   }      /**    * Replace spaces with "%20" and backslashes with forward slashes in     * the input string to generate a well-formed URI string.    *    * @param str The input string    * @return The string after conversion    */   private static String replaceChars(String str)   {     StringBuffer buf = new StringBuffer(str);     int length = buf.length();     for (int i = 0; i < length; i++)     {       char currentChar = buf.charAt(i);       // Replace space with "%20"       if (currentChar == ' ')       {         buf.setCharAt(i, '%');         buf.insert(i+1, "20");         length = length + 2;         i = i + 2;       }       // Replace backslash with forward slash       else if (currentChar == '\\')       {         buf.setCharAt(i, '/');       }     }          return buf.toString();   }      /**    * Take a SystemID string and try to turn it into a good absolute URI.    *    * @param systemId A URI string, which may be absolute or relative.    *    * @return The resolved absolute URI    */   public static String getAbsoluteURI(String systemId)   {     String absoluteURI = systemId;     if (isAbsoluteURI(systemId))     {       // Only process the systemId if it starts with "file:".       if (systemId.startsWith("file:"))       {         String str = systemId.substring(5);                  // Resolve the absolute path if the systemId starts with "file:///"         // or "file:/". Don't do anything if it only starts with "file://".         if (str != null && str.startsWith("/"))         {           if (str.startsWith("///") || !str.startsWith("//"))           {             // A Windows path containing a drive letter can be relative.             // A Unix path starting with "file:/" is always absolute.             int secondColonIndex = systemId.indexOf(':', 5);             if (secondColonIndex > 0)             {               String localPath = systemId.substring(secondColonIndex-1);               try {                 if (!isAbsolutePath(localPath))                   absoluteURI = systemId.substring(0, secondColonIndex-1) +                                  getAbsolutePathFromRelativePath(localPath);               }               catch (SecurityException se) {                 return systemId;               }             }           }                   }         else         {           return getAbsoluteURIFromRelative(systemId.substring(5));         }                          return replaceChars(absoluteURI);       }       else         return systemId;     }     else       return getAbsoluteURIFromRelative(systemId);        }    }