KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > xml > xdm > visitor > NamespaceRefactorVisitor


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.xml.xdm.visitor;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.HashSet JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Set JavaDoc;
26 import java.util.regex.Matcher JavaDoc;
27 import java.util.regex.Pattern JavaDoc;
28 import javax.xml.XMLConstants JavaDoc;
29 import javax.xml.namespace.QName JavaDoc;
30 import org.netbeans.modules.xml.xdm.XDMModel;
31 import org.netbeans.modules.xml.xdm.nodes.Attribute;
32 import org.netbeans.modules.xml.xdm.nodes.Element;
33 import org.netbeans.modules.xml.xdm.nodes.Node;
34 import org.netbeans.modules.xml.xdm.nodes.NodeImpl;
35 import org.w3c.dom.NamedNodeMap JavaDoc;
36
37 /**
38  *
39  * @author Nam Nguyen
40  */

41 public class NamespaceRefactorVisitor extends ChildVisitor {
42     private String JavaDoc namespace;
43     private String JavaDoc prefix;
44     private List JavaDoc<Node> path;
45     
46     // keep track of prefixes used by attributes so we avoid removing
47
// their declaration when the new prefix is default prefix.
48
private Set JavaDoc<String JavaDoc> prefixesUsedByAttributesForDefaultNS = new HashSet JavaDoc<String JavaDoc>();
49     
50     private XDMModel model;
51     
52     /**
53      * @deprecated use constructor with QName-valued attributes map. Prefix refactoring
54      * should not without complete map.
55      */

56     public NamespaceRefactorVisitor() {
57         this(null);
58     }
59     
60     public NamespaceRefactorVisitor(XDMModel xdmModel) {
61         model = xdmModel;
62     }
63     
64     public void refactor(NodeImpl tree, String JavaDoc namespace, String JavaDoc newPrefix, List JavaDoc<Node> ancestors) {
65         if (model.getQNameValuedAttributes() == null) return;
66         
67         assert namespace != null : "Cannot refactor null namespace";
68         this.namespace = namespace;
69         prefix = newPrefix;
70         path = ancestors;
71         tree.accept(this);
72     }
73     
74     public void visit(Element e) {
75         path.add(0, e);
76         NamespaceCheck redec = new NamespaceCheck(prefix, namespace, e);
77         if (redec.getPrefixRedeclaration() == null) {
78             visitNode(e);
79             
80             if (namespace.equals(NodeImpl.lookupNamespace(e.getPrefix(), path))) {
81                 e.setPrefix(prefix);
82             }
83
84             for (Attribute sameNamespace : redec.getNamespaceRedeclaration()) {
85                 String JavaDoc prefixToRemove = sameNamespace.getLocalName();
86                 if (! prefixesUsedByAttributesForDefaultNS.remove(prefixToRemove)) {
87                     e.removeAttributeNode(sameNamespace);
88                 }
89             }
90             
91             if (redec.getDuplicateDeclaration() != null) {
92                 e.removeAttributeNode(redec.getDuplicateDeclaration());
93             }
94         }
95         path.remove(e);
96     }
97     
98     public void visit(Attribute attr) {
99         if (attr.isXmlnsAttribute()) return;
100         String JavaDoc attrPrefix = attr.getPrefix();
101
102         // default namespace is not applicable for attribute, just have no namespaces.
103
if (! isDefaultPrefix(attrPrefix)) {
104             if (namespace.equals(NodeImpl.lookupNamespace(attrPrefix, path))) {
105                 if (isDefaultPrefix(prefix)) {
106                     prefixesUsedByAttributesForDefaultNS.add(attrPrefix);
107                 } else {
108                     attr.setPrefix(prefix);
109                 }
110             }
111         }
112         if (isQNameValued(attr)) {
113             prefixesUsedByAttributesForDefaultNS.addAll(
114                     refactorAttributeValue(attr, namespace, prefix, path, model));
115         }
116     }
117     
118     public static class NamespaceCheck {
119         Attribute duplicate;
120         Attribute prefixRedeclaration;
121         List JavaDoc<Attribute> namespaceRedeclaredAttributes = new ArrayList JavaDoc<Attribute>();
122         public NamespaceCheck(String JavaDoc existingPrefix, String JavaDoc existingNamespace, Element e) {
123             init(existingPrefix, existingNamespace, e);
124         }
125         public Attribute getPrefixRedeclaration() {
126             return prefixRedeclaration;
127         }
128         public List JavaDoc<Attribute> getNamespaceRedeclaration() {
129             return namespaceRedeclaredAttributes;
130         }
131         public Attribute getDuplicateDeclaration() {
132             return duplicate;
133         }
134         private void init(String JavaDoc existingPrefix, String JavaDoc existingNamespace, Element e) {
135             NamedNodeMap JavaDoc nnm = e.getAttributes();
136             for (int i=0; i<nnm.getLength(); i++) {
137                 if (! (nnm.item(i) instanceof Attribute)) continue;
138                 Attribute attr = (Attribute) nnm.item(i);
139                 if (attr.isXmlnsAttribute()) {
140                     Attribute samePrefix = null;
141                     Attribute sameNamespace = null;
142                     String JavaDoc prefix = attr.getLocalName();
143                     if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) {
144                         prefix = XMLConstants.DEFAULT_NS_PREFIX;
145                     }
146                     if (prefix.equals(existingPrefix)) {
147                         samePrefix = attr;
148                     }
149                     if (existingNamespace.equals(attr.getValue())) {
150                         sameNamespace = attr;
151                     }
152                     if (samePrefix != null && sameNamespace != null) {
153                         duplicate = attr;
154                     } else if (samePrefix != null) {
155                         prefixRedeclaration = attr;
156                     } else if (sameNamespace != null) {
157                         namespaceRedeclaredAttributes.add(attr);
158                     }
159                 }
160             }
161         }
162     }
163     
164     private QName JavaDoc getQName(Element node) {
165         String JavaDoc ns = NodeImpl.lookupNamespace(node.getPrefix(), path);
166         return new QName JavaDoc(ns, node.getLocalName());
167     }
168     
169     private QName JavaDoc getQName(Attribute node) {
170         String JavaDoc p = node.getPrefix();
171         String JavaDoc ns = (p == null || p.length() == 0) ? null : NodeImpl.lookupNamespace(p, path);
172         return new QName JavaDoc(ns, node.getLocalName());
173     }
174
175     private boolean isQNameValued(Attribute attr) {
176         assert path != null && path.size() > 0;
177         Element e = (Element) path.get(0);
178         QName JavaDoc elementQName = getQName(e);
179         QName JavaDoc attrQName = getQName(attr);
180         List JavaDoc<QName JavaDoc> attrQNames = model.getQNameValuedAttributes().get(elementQName);
181         if (attrQNames != null) {
182             return attrQNames.contains(attrQName);
183         }
184         return false;
185     }
186     
187     public static boolean isDefaultPrefix(String JavaDoc prefix) {
188         return prefix == null || prefix.equals(XMLConstants.DEFAULT_NS_PREFIX);
189     }
190
191     private static final Pattern JavaDoc p = Pattern.compile("\\s*(\\S+)\\s*");
192
193     public static List JavaDoc<String JavaDoc> refactorAttributeValue(Attribute attr,
194             String JavaDoc namespace, String JavaDoc prefix, List JavaDoc<Node> context, XDMModel model)
195     {
196         ArrayList JavaDoc<String JavaDoc> prefixesUsedForDefaultNS = new ArrayList JavaDoc<String JavaDoc>();
197         String JavaDoc value = attr.getValue();
198         StringBuilder JavaDoc newValue = null;
199         Matcher JavaDoc m = p.matcher(value);
200         while (m.find()) {
201             String JavaDoc qname = m.group(1);
202             String JavaDoc[] parts = qname.split(":");
203             if (parts.length > 1) {
204                 String JavaDoc valuePrefix = parts[0];
205                 String JavaDoc valueNamespace = context.size() == 1 ?
206                     context.get(0).lookupNamespaceURI(valuePrefix) :
207                     NodeImpl.lookupNamespace(valuePrefix, context);
208                 if (namespace.equals(valueNamespace)) {
209                     if (isDefaultPrefix(prefix)) {
210                         prefixesUsedForDefaultNS.add(valuePrefix);
211                     } else {
212                         if (newValue == null) newValue = new StringBuilder JavaDoc();
213                         newValue.append(prefix);
214                         newValue.append(":");
215                         newValue.append(parts[1]);
216                         newValue.append(" ");
217                     }
218                 }
219             }
220         }
221         if (newValue != null) {
222             attr.setValue(newValue.toString().trim());
223         }
224         return prefixesUsedForDefaultNS;
225     }
226 }
227
Popular Tags