1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
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
17package com.android.xml;
18
19import com.android.SdkConstants;
20
21import java.util.Collections;
22import java.util.Iterator;
23import java.util.List;
24
25import javax.xml.XMLConstants;
26import javax.xml.namespace.NamespaceContext;
27import javax.xml.xpath.XPath;
28import javax.xml.xpath.XPathFactory;
29
30/**
31 * XPath factory with automatic support for the android name space.
32 */
33public class AndroidXPathFactory {
34    /** Default prefix for android name space: 'android' */
35    public final static String DEFAULT_NS_PREFIX = "android"; //$NON-NLS-1$
36
37    private final static XPathFactory sFactory = XPathFactory.newInstance();
38
39    /** Name space context for Android resource XML files. */
40    private static class AndroidNamespaceContext implements NamespaceContext {
41        private final static AndroidNamespaceContext sThis = new AndroidNamespaceContext(
42                DEFAULT_NS_PREFIX);
43
44        private final String mAndroidPrefix;
45        private final List<String> mAndroidPrefixes;
46
47        /**
48         * Returns the default {@link AndroidNamespaceContext}.
49         */
50        private static AndroidNamespaceContext getDefault() {
51            return sThis;
52        }
53
54        /**
55         * Construct the context with the prefix associated with the android namespace.
56         * @param androidPrefix the Prefix
57         */
58        public AndroidNamespaceContext(String androidPrefix) {
59            mAndroidPrefix = androidPrefix;
60            mAndroidPrefixes = Collections.singletonList(mAndroidPrefix);
61        }
62
63        @Override
64        public String getNamespaceURI(String prefix) {
65            if (prefix != null) {
66                if (prefix.equals(mAndroidPrefix)) {
67                    return SdkConstants.NS_RESOURCES;
68                }
69            }
70
71            return XMLConstants.NULL_NS_URI;
72        }
73
74        @Override
75        public String getPrefix(String namespaceURI) {
76            if (SdkConstants.NS_RESOURCES.equals(namespaceURI)) {
77                return mAndroidPrefix;
78            }
79
80            return null;
81        }
82
83        @Override
84        public Iterator<?> getPrefixes(String namespaceURI) {
85            if (SdkConstants.NS_RESOURCES.equals(namespaceURI)) {
86                return mAndroidPrefixes.iterator();
87            }
88
89            return null;
90        }
91    }
92
93    /**
94     * Creates a new XPath object, specifying which prefix in the query is used for the
95     * android namespace.
96     * @param androidPrefix The namespace prefix.
97     */
98    public static XPath newXPath(String androidPrefix) {
99        XPath xpath = sFactory.newXPath();
100        xpath.setNamespaceContext(new AndroidNamespaceContext(androidPrefix));
101        return xpath;
102    }
103
104    /**
105     * Creates a new XPath object using the default prefix for the android namespace.
106     * @see #DEFAULT_NS_PREFIX
107     */
108    public static XPath newXPath() {
109        XPath xpath = sFactory.newXPath();
110        xpath.setNamespaceContext(AndroidNamespaceContext.getDefault());
111        return xpath;
112    }
113}
114