/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php * * 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. */ package com.android.ide.eclipse.adt.refactorings.extractstring; import com.android.ide.eclipse.common.project.AndroidXPathFactory; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import java.util.HashMap; import java.util.HashSet; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; /** * */ class XmlStringFileHelper { /** A temporary cache of R.string IDs defined by a given xml file. The key is the * project path of the file, the data is a set of known string Ids for that file. */ private HashMap<String,HashSet<String>> mResIdCache; /** An instance of XPath, created lazily on demand. */ private XPath mXPath; public XmlStringFileHelper() { } /** * Utility method used by the wizard to check whether the given string ID is already * defined in the XML file which path is given. * * @param project The project contain the XML file. * @param xmlFileWsPath The project path of the XML file, e.g. "/res/values/strings.xml". * The given file may or may not exist. * @param stringId The string ID to find. * @return True if such a string ID is already defined. */ public boolean isResIdDuplicate(IProject project, String xmlFileWsPath, String stringId) { // This is going to be called many times on the same file. // Build a cache of the existing IDs for a given file. if (mResIdCache == null) { mResIdCache = new HashMap<String, HashSet<String>>(); } HashSet<String> cache = mResIdCache.get(xmlFileWsPath); if (cache == null) { cache = getResIdsForFile(project, xmlFileWsPath); mResIdCache.put(xmlFileWsPath, cache); } return cache.contains(stringId); } /** * Extract all the defined string IDs from a given file using XPath. * @param project The project contain the XML file. * @param xmlFileWsPath The project path of the file to parse. It may not exist. * @return The set of all string IDs defined in the file. The returned set is always non * null. It is empty if the file does not exist. */ private HashSet<String> getResIdsForFile(IProject project, String xmlFileWsPath) { HashSet<String> ids = new HashSet<String>(); if (mXPath == null) { mXPath = AndroidXPathFactory.newXPath(); } // Access the project that contains the resource that contains the compilation unit IResource resource = project.getFile(xmlFileWsPath); if (resource != null && resource.exists() && resource.getType() == IResource.FILE) { InputSource source; try { source = new InputSource(((IFile) resource).getContents()); // We want all the IDs in an XML structure like this: // <resources> // <string name="ID">something</string> // </resources> String xpathExpr = "/resources/string/@name"; //$NON-NLS-1$ Object result = mXPath.evaluate(xpathExpr, source, XPathConstants.NODESET); if (result instanceof NodeList) { NodeList list = (NodeList) result; for (int n = list.getLength() - 1; n >= 0; n--) { String id = list.item(n).getNodeValue(); ids.add(id); } } } catch (CoreException e1) { // IFile.getContents failed. Ignore. } catch (XPathExpressionException e) { // mXPath.evaluate failed. Ignore. } } return ids; } }