1 19 20 package org.netbeans.modules.xml.xdm.visitor; 21 22 import java.util.ArrayList ; 23 import java.util.HashSet ; 24 import java.util.List ; 25 import java.util.Set ; 26 import java.util.regex.Matcher ; 27 import java.util.regex.Pattern ; 28 import javax.xml.XMLConstants ; 29 import javax.xml.namespace.QName ; 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 ; 36 37 41 public class NamespaceRefactorVisitor extends ChildVisitor { 42 private String namespace; 43 private String prefix; 44 private List <Node> path; 45 46 private Set <String > prefixesUsedByAttributesForDefaultNS = new HashSet <String >(); 49 50 private XDMModel model; 51 52 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 namespace, String newPrefix, List <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 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 attrPrefix = attr.getPrefix(); 101 102 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 <Attribute> namespaceRedeclaredAttributes = new ArrayList <Attribute>(); 122 public NamespaceCheck(String existingPrefix, String existingNamespace, Element e) { 123 init(existingPrefix, existingNamespace, e); 124 } 125 public Attribute getPrefixRedeclaration() { 126 return prefixRedeclaration; 127 } 128 public List <Attribute> getNamespaceRedeclaration() { 129 return namespaceRedeclaredAttributes; 130 } 131 public Attribute getDuplicateDeclaration() { 132 return duplicate; 133 } 134 private void init(String existingPrefix, String existingNamespace, Element e) { 135 NamedNodeMap 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 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 getQName(Element node) { 165 String ns = NodeImpl.lookupNamespace(node.getPrefix(), path); 166 return new QName (ns, node.getLocalName()); 167 } 168 169 private QName getQName(Attribute node) { 170 String p = node.getPrefix(); 171 String ns = (p == null || p.length() == 0) ? null : NodeImpl.lookupNamespace(p, path); 172 return new QName (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 elementQName = getQName(e); 179 QName attrQName = getQName(attr); 180 List <QName > 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 prefix) { 188 return prefix == null || prefix.equals(XMLConstants.DEFAULT_NS_PREFIX); 189 } 190 191 private static final Pattern p = Pattern.compile("\\s*(\\S+)\\s*"); 192 193 public static List <String > refactorAttributeValue(Attribute attr, 194 String namespace, String prefix, List <Node> context, XDMModel model) 195 { 196 ArrayList <String > prefixesUsedForDefaultNS = new ArrayList <String >(); 197 String value = attr.getValue(); 198 StringBuilder newValue = null; 199 Matcher m = p.matcher(value); 200 while (m.find()) { 201 String qname = m.group(1); 202 String [] parts = qname.split(":"); 203 if (parts.length > 1) { 204 String valuePrefix = parts[0]; 205 String 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 (); 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 |