| /* |
| * Copyright 2002-2005 Sascha Weinreuter |
| * |
| * Licensed 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. |
| */ |
| package org.intellij.plugins.xpathView.util; |
| |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.psi.XmlRecursiveElementVisitor; |
| import com.intellij.psi.xml.XmlAttribute; |
| import com.intellij.psi.xml.XmlDocument; |
| import com.intellij.psi.xml.XmlFile; |
| import com.intellij.psi.xml.XmlTag; |
| |
| import javax.xml.namespace.QName; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedHashSet; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /** |
| * Helper class to collect all used namespaces and their prefixes from an xml document |
| */ |
| public class NamespaceCollector extends XmlRecursiveElementVisitor { |
| private static final Logger LOG = Logger.getInstance("org.intellij.plugins.xpathView.util.NamespaceCollector"); |
| |
| public static class CollectedInfo { |
| public final Set<Namespace> namespaces; |
| public final Set<QName> elements; |
| public final Set<QName> attributes; |
| |
| CollectedInfo(Set<Namespace> namespaces, Set<QName> elements, Set<QName> attributes) { |
| this.namespaces = Collections.unmodifiableSet(namespaces); |
| this.elements = Collections.unmodifiableSet(elements); |
| this.attributes = Collections.unmodifiableSet(attributes); |
| } |
| } |
| |
| private final Set<Namespace> namespaces = new LinkedHashSet<Namespace>(); |
| private final Set<QName> elements = new HashSet<QName>(64); |
| private final Set<QName> attributes = new HashSet<QName>(64); |
| |
| private NamespaceCollector() { |
| |
| } |
| |
| public Set<Namespace> getNamespaces() { |
| return namespaces; |
| } |
| |
| @Override |
| public void visitXmlAttribute(XmlAttribute xmlAttribute) { |
| if (xmlAttribute.isNamespaceDeclaration()) { |
| LOG.debug("Namespace: " + xmlAttribute.getLocalName() + " => " + xmlAttribute.getValue()); |
| addNamespace(xmlAttribute.getLocalName(), xmlAttribute.getValue()); |
| } else { |
| addAttribute(xmlAttribute); |
| } |
| } |
| |
| @Override |
| public void visitXmlTag(XmlTag tag) { |
| final Map<String, String> namespaceDeclarations = tag.getLocalNamespaceDeclarations(); |
| final Set<String> localPrefixes = namespaceDeclarations.keySet(); |
| for (String prefix : localPrefixes) { |
| // More namespace fun... |
| // [IDEA-5883] XmlTag.getLocalNamespaceDeclarations() return "xmlns" for default ("") namespace |
| addNamespace("xmlns".equals(prefix) ? "" : prefix, namespaceDeclarations.get(prefix)); |
| } |
| addElement(tag); |
| super.visitXmlTag(tag); |
| } |
| |
| private void addAttribute(XmlAttribute xmlAttribute) { |
| final String namespace = xmlAttribute.getNamespace(); |
| final String localName = xmlAttribute.getLocalName(); |
| // [IDEA-5206] XmlAttribute.getNamespace() returns namespace of parent element if no prefix in attribute name. That's wrong |
| final String name = xmlAttribute.getName(); |
| if (name.indexOf(':') == -1) { |
| attributes.add(new QName("", localName)); |
| } else { |
| attributes.add(new QName(namespace, localName)); |
| } |
| } |
| |
| private void addElement(XmlTag tag) { |
| final String uri = tag.getNamespace(); |
| final String prefix = tag.getNamespacePrefix(); |
| // [IDEA-5885] IDEA assigns System-URI of DTD as namespace. |
| if (MyPsiUtil.isInDeclaredNamespace(tag, uri, prefix)) { |
| elements.add(new QName(uri, tag.getLocalName(), prefix)); |
| } else { |
| elements.add(new QName("", tag.getLocalName(), "")); |
| } |
| } |
| |
| private void addNamespace(final String prefix, final String value) { |
| if (value.length() > 0) { |
| final Namespace namespace = new Namespace(prefix, value); |
| namespaces.add(namespace); |
| } |
| } |
| |
| public static Set<Namespace> findAllNamespaces(final XmlFile psiFile) { |
| final NamespaceCollector namespaceCollector = new NamespaceCollector(); |
| final XmlDocument document = psiFile.getDocument(); |
| if (document != null) { |
| document.accept(namespaceCollector); |
| } |
| return namespaceCollector.namespaces; |
| } |
| |
| public static CollectedInfo empty() { |
| //noinspection unchecked |
| return new CollectedInfo(Collections.<Namespace>emptySet(), Collections.<QName>emptySet(), Collections.<QName>emptySet()); |
| } |
| |
| public static CollectedInfo collectInfo(final XmlFile psiFile) { |
| final NamespaceCollector namespaceCollector = new NamespaceCollector(); |
| final XmlDocument document = psiFile.getDocument(); |
| if (document != null) { |
| document.accept(namespaceCollector); |
| } |
| return new CollectedInfo(namespaceCollector.namespaces, namespaceCollector.elements, namespaceCollector.attributes); |
| } |
| |
| public static Map<String,String> findNamespaces(final XmlFile psiFile) { |
| final NamespaceCollector namespaceCollector = new NamespaceCollector(); |
| final XmlDocument document = psiFile.getDocument(); |
| if (document != null) { |
| document.accept(namespaceCollector); |
| } |
| final Set<Namespace> namespaces = namespaceCollector.namespaces; |
| |
| return convert(namespaces); |
| } |
| |
| public static Map<String, String> convert(final Collection<Namespace> namespaces) { |
| final Map<String, String> map = new HashMap<String, String>(); |
| for (Namespace namespace : namespaces) { |
| if (!map.containsKey(namespace.getPrefix())) { |
| map.put(namespace.getPrefix(), namespace.getUri()); |
| } |
| } |
| return map; |
| } |
| } |