mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-53813
This commit is contained in:
+148
-64
@@ -15,22 +15,23 @@
|
||||
*/
|
||||
package org.intellij.plugins.xpathView;
|
||||
|
||||
import org.intellij.plugins.xpathView.support.XPathSupport;
|
||||
import org.intellij.plugins.xpathView.support.jaxen.PsiDocumentNavigator;
|
||||
import org.intellij.plugins.xpathView.util.MyPsiUtil;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.XmlElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.xml.*;
|
||||
import com.intellij.xml.XmlAttributeDescriptor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import org.intellij.plugins.xpathView.support.XPathSupport;
|
||||
import org.intellij.plugins.xpathView.support.jaxen.PsiDocumentNavigator;
|
||||
import org.intellij.plugins.xpathView.util.MyPsiUtil;
|
||||
import org.intellij.plugins.xpathView.util.Namespace;
|
||||
import org.jaxen.JaxenException;
|
||||
import org.jaxen.XPath;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class XPathExpressionGenerator {
|
||||
private static final XPathSupport xpathSupport = XPathSupport.getInstance();
|
||||
@@ -44,59 +45,6 @@ public class XPathExpressionGenerator {
|
||||
return visitor.getUniquePath();
|
||||
}
|
||||
|
||||
static String makeUnique(String uniquePath, XmlElement what) {
|
||||
final XmlFile file = (XmlFile)what.getContainingFile();
|
||||
assert file != null;
|
||||
try {
|
||||
final XPath xPath = xpathSupport.createXPath(file, uniquePath);
|
||||
final Object o = xPath.evaluate(file.getDocument());
|
||||
if (o instanceof List) {
|
||||
//noinspection RawUseOfParameterizedType
|
||||
final List list = (List)o;
|
||||
if (list.size() > 1) {
|
||||
if (what instanceof XmlTag) {
|
||||
final XmlTag tag = (XmlTag)what;
|
||||
final XmlAttribute[] attributes = tag.getAttributes();
|
||||
if (attributes.length > 0) {
|
||||
for (XmlAttribute attribute : attributes) {
|
||||
final String name = attribute.getName();
|
||||
final XmlAttributeDescriptor descriptor = attribute.getDescriptor();
|
||||
if ((attribute.getValue() != null &&
|
||||
(descriptor != null && descriptor.hasIdType()) ||
|
||||
name.equalsIgnoreCase("id") ||
|
||||
name.equalsIgnoreCase("name")))
|
||||
{
|
||||
final StringBuilder buffer = new StringBuilder(uniquePath);
|
||||
buffer.append("[@");
|
||||
buffer.append(name);
|
||||
buffer.append("='");
|
||||
buffer.append(attribute.getValue());
|
||||
buffer.append("']");
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int i = 1;
|
||||
for (Object o1 : list) {
|
||||
if (o1 == what) {
|
||||
return uniquePath + "[" + i + "]";
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
assert false : "Expression " + uniquePath + " didn't find input element " + what;
|
||||
}
|
||||
} else {
|
||||
assert false : "Unknown return value: " + o;
|
||||
}
|
||||
} catch (JaxenException e) {
|
||||
Logger.getInstance("XPathExpressionGenerator").error(e);
|
||||
}
|
||||
return uniquePath;
|
||||
}
|
||||
|
||||
public static String getPath(XmlElement element, XmlTag context) {
|
||||
final PathVisitor visitor = new PathVisitor(context);
|
||||
element.accept(visitor);
|
||||
@@ -128,6 +76,7 @@ public class XPathExpressionGenerator {
|
||||
|
||||
private static class PathVisitor extends XmlElementVisitor {
|
||||
private final XmlTag context;
|
||||
private final Map<String, String> usedPrefixes = new HashMap<String, String>();
|
||||
private String uniquePath;
|
||||
private String path;
|
||||
|
||||
@@ -136,7 +85,7 @@ public class XPathExpressionGenerator {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getXPathNameStep(XmlTag tag) {
|
||||
private String getXPathNameStep(XmlTag tag) {
|
||||
String uri = tag.getNamespace();
|
||||
|
||||
if ((uri.length() == 0)) {
|
||||
@@ -146,14 +95,93 @@ public class XPathExpressionGenerator {
|
||||
if (MyPsiUtil.isInDeclaredNamespace(tag, uri, tag.getNamespacePrefix())) {
|
||||
String prefix = tag.getNamespacePrefix();
|
||||
|
||||
// TODO: could be even more strict by checking namespace-uri() equivalence here but would look ugly
|
||||
if (prefix.length() == 0) {
|
||||
return "*[name()='" + tag.getName() + "']";
|
||||
final String guessedPrefix = guessPrefix(tag);
|
||||
return guessedPrefix != null ? guessedPrefix + ":" + tag.getLocalName() : "*[name()='" + tag.getName() + "']";
|
||||
}
|
||||
}
|
||||
return tag.getName();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String guessPrefix(XmlTag tag) {
|
||||
final String prefix = usedPrefixes.get(tag.getNamespace());
|
||||
if (prefix != null) {
|
||||
return prefix;
|
||||
}
|
||||
return tryUseUri(tag);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String tryUseUri(XmlTag context) {
|
||||
String segment = chooseSegment(context.getNamespace());
|
||||
if (segment == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (segment.length() <= 3 && tryUsePrefix(segment, context)) {
|
||||
return segment;
|
||||
}
|
||||
|
||||
for (int i = 1; i <= segment.length(); i++) {
|
||||
String prefix = segment.substring(0, i);
|
||||
if (tryUsePrefix(prefix, context)) return prefix;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean tryUsePrefix(String prefix, XmlTag context) {
|
||||
if (!prefixOk(prefix, context)) return false;
|
||||
usePrefix(prefix, context.getNamespace());
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean prefixOk(String prefix, XmlTag context) {
|
||||
final String namespace = context.getNamespace();
|
||||
if (!usedPrefixes.containsKey(prefix)) {
|
||||
final String ns = context.getNamespaceByPrefix(prefix);
|
||||
if (ns.length() == 0 || ns.equals(namespace)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return namespace.equals(usedPrefixes.get(prefix));
|
||||
}
|
||||
|
||||
private void usePrefix(String prefix, String namespace) {
|
||||
usedPrefixes.put(prefix, namespace);
|
||||
}
|
||||
|
||||
static private String chooseSegment(String ns) {
|
||||
int off = ns.indexOf('#');
|
||||
if (off >= 0) {
|
||||
String segment = ns.substring(off + 1).toLowerCase();
|
||||
if (isValidPrefix(segment)) return segment;
|
||||
} else {
|
||||
off = ns.length();
|
||||
}
|
||||
for (; ;) {
|
||||
int i = ns.lastIndexOf('/', off - 1);
|
||||
if (i < 0 || (i > 0 && ns.charAt(i - 1) == '/')) break;
|
||||
String segment = ns.substring(i + 1, off).toLowerCase();
|
||||
if (segmentOk(segment)) return segment;
|
||||
off = i;
|
||||
}
|
||||
off = ns.indexOf(':');
|
||||
if (off >= 0) {
|
||||
String segment = ns.substring(off + 1).toLowerCase();
|
||||
if (segmentOk(segment)) return segment;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isValidPrefix(String segment) {
|
||||
return segment.matches("\\p{Alpha}\\p{Alnum}*");
|
||||
}
|
||||
|
||||
private static boolean segmentOk(String segment) {
|
||||
return isValidPrefix(segment) && !segment.equals("ns") && !segment.equals("namespace");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (element instanceof XmlProcessingInstruction) {
|
||||
@@ -266,12 +294,14 @@ public class XPathExpressionGenerator {
|
||||
uniquePath = getUniquePath(comment);
|
||||
path = getPath(comment);
|
||||
}
|
||||
|
||||
public String getPath(XmlComment comment) {
|
||||
XmlTag parent = PsiTreeUtil.getParentOfType(comment, XmlTag.class);
|
||||
|
||||
return ((parent != null) && (parent != context)) ? (getPath(parent) + "/comment()")
|
||||
: "comment()";
|
||||
: "comment()";
|
||||
}
|
||||
|
||||
public String getUniquePath(XmlComment comment) {
|
||||
XmlTag parent = PsiTreeUtil.getParentOfType(comment, XmlTag.class);
|
||||
|
||||
@@ -284,12 +314,14 @@ public class XPathExpressionGenerator {
|
||||
uniquePath = getUniquePath(text);
|
||||
path = getPath(text);
|
||||
}
|
||||
|
||||
public String getPath(XmlText text) {
|
||||
XmlTag parent = PsiTreeUtil.getParentOfType(text, XmlTag.class);
|
||||
|
||||
return ((parent != null) && (parent != context)) ? (getPath(parent) + "/text()")
|
||||
: "text()";
|
||||
: "text()";
|
||||
}
|
||||
|
||||
public String getUniquePath(XmlText text) {
|
||||
XmlTag parent = PsiTreeUtil.getParentOfType(text, XmlTag.class);
|
||||
|
||||
@@ -325,5 +357,57 @@ public class XPathExpressionGenerator {
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
String makeUnique(String uniquePath, XmlElement what) {
|
||||
final XmlFile file = (XmlFile)what.getContainingFile();
|
||||
assert file != null;
|
||||
try {
|
||||
final XPath xPath = xpathSupport.createXPath(file, uniquePath, Namespace.fromMap(usedPrefixes));
|
||||
final Object o = xPath.evaluate(file.getDocument());
|
||||
if (o instanceof List) {
|
||||
//noinspection RawUseOfParameterizedType
|
||||
final List list = (List)o;
|
||||
if (list.size() > 1) {
|
||||
if (what instanceof XmlTag) {
|
||||
final XmlTag tag = (XmlTag)what;
|
||||
final XmlAttribute[] attributes = tag.getAttributes();
|
||||
if (attributes.length > 0) {
|
||||
for (XmlAttribute attribute : attributes) {
|
||||
final String name = attribute.getName();
|
||||
final XmlAttributeDescriptor descriptor = attribute.getDescriptor();
|
||||
if ((attribute.getValue() != null &&
|
||||
(descriptor != null && descriptor.hasIdType()) ||
|
||||
name.equalsIgnoreCase("id") ||
|
||||
name.equalsIgnoreCase("name"))) {
|
||||
final StringBuilder buffer = new StringBuilder(uniquePath);
|
||||
buffer.append("[@");
|
||||
buffer.append(name);
|
||||
buffer.append("='");
|
||||
buffer.append(attribute.getValue());
|
||||
buffer.append("']");
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int i = 1;
|
||||
for (Object o1 : list) {
|
||||
if (o1 == what) {
|
||||
return uniquePath + "[" + i + "]";
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
assert false : "Expression " + uniquePath + " didn't find input element " + what;
|
||||
}
|
||||
} else {
|
||||
assert false : "Unknown return value: " + o;
|
||||
}
|
||||
} catch (JaxenException e) {
|
||||
Logger.getInstance("XPathExpressionGenerator").error(e);
|
||||
}
|
||||
return uniquePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
*/
|
||||
package org.intellij.plugins.xpathView.util;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.*;
|
||||
|
||||
public final class Namespace implements Cloneable, Copyable<Namespace> {
|
||||
public String prefix;
|
||||
@@ -65,6 +63,14 @@ public final class Namespace implements Cloneable, Copyable<Namespace> {
|
||||
return clone();
|
||||
}
|
||||
|
||||
public static Collection<Namespace> fromMap(Map<String, String> namespaces) {
|
||||
final List<Namespace> list = new ArrayList<Namespace>(namespaces.size());
|
||||
for (Map.Entry<String, String> e : namespaces.entrySet()) {
|
||||
list.add(new Namespace(e.getKey(), e.getValue()));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static Map<String, String> makeMap(Collection<Namespace> namespaces) {
|
||||
final Map<String, String> _ns = new HashMap<String, String>();
|
||||
for (Namespace namespace : namespaces) {
|
||||
|
||||
Reference in New Issue
Block a user