• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.eclipse.org/org/documents/epl-v10.php
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.ide.eclipse.adt.internal.refactorings.extractstring;
18 
19 import com.android.sdklib.xml.AndroidXPathFactory;
20 
21 import org.eclipse.core.resources.IFile;
22 import org.eclipse.core.resources.IProject;
23 import org.eclipse.core.resources.IResource;
24 import org.eclipse.core.runtime.CoreException;
25 import org.w3c.dom.NamedNodeMap;
26 import org.w3c.dom.Node;
27 import org.w3c.dom.NodeList;
28 import org.xml.sax.InputSource;
29 
30 import java.util.HashMap;
31 import java.util.Map;
32 import java.util.TreeMap;
33 
34 import javax.xml.xpath.XPath;
35 import javax.xml.xpath.XPathConstants;
36 import javax.xml.xpath.XPathExpressionException;
37 
38 /**
39  * An helper utility to get IDs out of an Android XML resource file.
40  */
41 class XmlStringFileHelper {
42 
43     /** A temporary cache of R.string IDs defined by a given xml file. The key is the
44      * project path of the file, the data is a set of known string Ids for that file.
45      *
46      * Map type: map [String filename] => map [String id => String value].
47      */
48     private HashMap<String, Map<String, String>> mResIdCache =
49         new HashMap<String, Map<String, String>>();
50     /** An instance of XPath, created lazily on demand. */
51     private XPath mXPath;
52 
XmlStringFileHelper()53     public XmlStringFileHelper() {
54     }
55 
56     /**
57      * Utility method used by the wizard to retrieve the actual value definition of a given
58      * string ID.
59      *
60      * @param project The project contain the XML file.
61      * @param xmlFileWsPath The project path of the XML file, e.g. "/res/values/strings.xml".
62      *          The given file may or may not exist.
63      * @param stringId The string ID to find.
64      * @return The value string if the ID is defined, null otherwise.
65      */
valueOfStringId(IProject project, String xmlFileWsPath, String stringId)66     public String valueOfStringId(IProject project, String xmlFileWsPath, String stringId) {
67         Map<String, String> cache = getResIdsForFile(project, xmlFileWsPath);
68         return cache.get(stringId);
69     }
70 
71     /**
72      * Utility method that retrieves all the *string* IDs defined in the given Android resource
73      * file. The instance maintains an internal cache so a given file is retrieved only once.
74      * Callers should consider the set to be read-only.
75      *
76      * @param project The project contain the XML file.
77      * @param xmlFileWsPath The project path of the XML file, e.g. "/res/values/strings.xml".
78      *          The given file may or may not exist.
79      * @return The map of string IDs => values defined in the given file. Cached. Never null.
80      */
getResIdsForFile(IProject project, String xmlFileWsPath)81     public Map<String, String> getResIdsForFile(IProject project, String xmlFileWsPath) {
82         Map<String, String> cache = mResIdCache.get(xmlFileWsPath);
83         if (cache == null) {
84             cache = internalGetResIdsForFile(project, xmlFileWsPath);
85             mResIdCache.put(xmlFileWsPath, cache);
86         }
87         return cache;
88     }
89 
90     /**
91      * Extract all the defined string IDs from a given file using XPath.
92      * @param project The project contain the XML file.
93      * @param xmlFileWsPath The project path of the file to parse. It may not exist.
94      * @return The map of all string IDs => values defined in the file.
95      *   The returned set is always non null. It is empty if the file does not exist.
96      */
internalGetResIdsForFile(IProject project, String xmlFileWsPath)97     private Map<String, String> internalGetResIdsForFile(IProject project, String xmlFileWsPath) {
98         TreeMap<String, String> ids = new TreeMap<String, String>();
99 
100         if (mXPath == null) {
101             mXPath = AndroidXPathFactory.newXPath();
102         }
103 
104         // Access the project that contains the resource that contains the compilation unit
105         IResource resource = project.getFile(xmlFileWsPath);
106 
107         if (resource != null && resource.exists() && resource.getType() == IResource.FILE) {
108             InputSource source;
109             try {
110                 source = new InputSource(((IFile) resource).getContents());
111 
112                 // We want all the IDs in an XML structure like this:
113                 // <resources>
114                 //    <string name="ID">something</string>
115                 // </resources>
116 
117                 String xpathExpr = "/resources/string";                         //$NON-NLS-1$
118 
119                 Object result = mXPath.evaluate(xpathExpr, source, XPathConstants.NODESET);
120                 if (result instanceof NodeList) {
121                     NodeList list = (NodeList) result;
122                     for (int n = list.getLength() - 1; n >= 0; n--) {
123                         Node strNode = list.item(n);
124                         NamedNodeMap attrs = strNode.getAttributes();
125                         Node nameAttr = attrs.getNamedItem("name");             //$NON-NLS-1$
126                         if (nameAttr != null) {
127                             String id = nameAttr.getNodeValue();
128                             String text = strNode.getTextContent();
129                             ids.put(id, text);
130                         }
131                     }
132                 }
133 
134             } catch (CoreException e1) {
135                 // IFile.getContents failed. Ignore.
136             } catch (XPathExpressionException e2) {
137                 // mXPath.evaluate failed. Ignore.
138             }
139         }
140 
141         return ids;
142     }
143 
144 }
145