summaryrefslogtreecommitdiff
path: root/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/XmlMatchingVisitor.java
diff options
context:
space:
mode:
Diffstat (limited to 'platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/XmlMatchingVisitor.java')
-rw-r--r--platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/XmlMatchingVisitor.java130
1 files changed, 130 insertions, 0 deletions
diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/XmlMatchingVisitor.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/XmlMatchingVisitor.java
new file mode 100644
index 000000000000..d2e1e210534b
--- /dev/null
+++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/XmlMatchingVisitor.java
@@ -0,0 +1,130 @@
+package com.intellij.structuralsearch.impl.matcher;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiWhiteSpace;
+import com.intellij.psi.XmlElementVisitor;
+import com.intellij.psi.util.PsiUtilCore;
+import com.intellij.psi.xml.*;
+import com.intellij.structuralsearch.impl.matcher.handlers.MatchingHandler;
+import com.intellij.structuralsearch.impl.matcher.handlers.SubstitutionHandler;
+import com.intellij.dupLocator.iterators.ArrayBackedNodeIterator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+* @author Eugene.Kudelevsky
+*/
+public class XmlMatchingVisitor extends XmlElementVisitor {
+ private final GlobalMatchingVisitor myMatchingVisitor;
+ private final boolean myCaseSensitive;
+
+ public XmlMatchingVisitor(GlobalMatchingVisitor matchingVisitor) {
+ myMatchingVisitor = matchingVisitor;
+ myCaseSensitive = myMatchingVisitor.getMatchContext().getOptions().isCaseSensitiveMatch();
+ }
+
+ @Override
+ public void visitElement(final PsiElement element) {
+ myMatchingVisitor.setResult(element.textMatches(element));
+ }
+
+ @Override public void visitXmlAttribute(XmlAttribute attribute) {
+ final XmlAttribute another = (XmlAttribute)myMatchingVisitor.getElement();
+ final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(attribute.getName());
+
+ myMatchingVisitor.setResult(matches(attribute.getName(), another.getName()) || isTypedVar);
+ if (myMatchingVisitor.getResult()) {
+ myMatchingVisitor.setResult(myMatchingVisitor.match(attribute.getValueElement(), another.getValueElement()));
+ }
+
+ if (myMatchingVisitor.getResult() && isTypedVar) {
+ MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler(attribute.getName());
+ myMatchingVisitor.setResult(((SubstitutionHandler)handler).handle(another, myMatchingVisitor.getMatchContext()));
+ }
+ }
+
+ @Override public void visitXmlAttributeValue(XmlAttributeValue value) {
+ final XmlAttributeValue another = (XmlAttributeValue)myMatchingVisitor.getElement();
+ final String text = value.getValue();
+
+ final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(text);
+ MatchingHandler handler;
+
+ if (isTypedVar && (handler = myMatchingVisitor.getMatchContext().getPattern().getHandler( text )) instanceof SubstitutionHandler) {
+ String text2 = another.getText();
+ int offset = text2.length() > 0 && ( text2.charAt(0) == '"' || text2.charAt(0) == '\'') ? 1:0;
+ myMatchingVisitor.setResult(((SubstitutionHandler)handler).handle(another, offset, text2.length() - offset,
+ myMatchingVisitor.getMatchContext()));
+ } else {
+ myMatchingVisitor.setResult(matches(text, another.getValue()));
+ }
+ }
+
+ @Override public void visitXmlTag(XmlTag tag) {
+ final XmlTag another = (XmlTag)myMatchingVisitor.getElement();
+ final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(tag.getName());
+
+ myMatchingVisitor.setResult((matches(tag.getName(), another.getName()) || isTypedVar) &&
+ myMatchingVisitor.matchInAnyOrder(tag.getAttributes(), another.getAttributes()));
+
+ if(myMatchingVisitor.getResult()) {
+ final XmlTagChild[] contentChildren = tag.getValue().getChildren();
+
+ if (contentChildren.length > 0) {
+ PsiElement[] patternNodes = contentChildren;
+ PsiElement[] matchedNodes = another.getValue().getChildren();
+
+ if (contentChildren.length != 1) {
+ patternNodes = expandXmlTexts(patternNodes);
+ matchedNodes = expandXmlTexts(matchedNodes);
+ }
+
+ myMatchingVisitor.setResult(myMatchingVisitor.matchSequentially(
+ new ArrayBackedNodeIterator(patternNodes),
+ new ArrayBackedNodeIterator(matchedNodes)
+ ));
+ }
+ }
+
+ if (myMatchingVisitor.getResult() && isTypedVar) {
+ MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler( tag.getName() );
+ myMatchingVisitor.setResult(((SubstitutionHandler)handler).handle(another, myMatchingVisitor.getMatchContext()));
+ }
+ }
+
+ private static PsiElement[] expandXmlTexts(PsiElement[] children) {
+ List<PsiElement> result = new ArrayList<PsiElement>(children.length);
+ for(PsiElement c:children) {
+ if (c instanceof XmlText) {
+ for(PsiElement p:c.getChildren()) {
+ if (!(p instanceof PsiWhiteSpace)) result.add(p);
+ }
+ } else if (!(c instanceof PsiWhiteSpace)) {
+ result.add(c);
+ }
+ }
+ return PsiUtilCore.toPsiElementArray(result);
+ }
+
+ @Override public void visitXmlText(XmlText text) {
+ myMatchingVisitor.setResult(myMatchingVisitor.matchSequentially(text.getFirstChild(), myMatchingVisitor.getElement().getFirstChild()));
+ }
+
+ @Override public void visitXmlToken(XmlToken token) {
+ if (token.getTokenType() == XmlTokenType.XML_DATA_CHARACTERS) {
+ String text = token.getText();
+ final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(text);
+
+ if (isTypedVar) {
+ myMatchingVisitor.setResult(myMatchingVisitor.handleTypedElement(token, myMatchingVisitor.getElement()));
+ } else {
+ myMatchingVisitor.setResult(matches(text, myMatchingVisitor.getElement().getText()));
+ }
+ }
+ }
+
+ private boolean matches(String a, String b) {
+ return myCaseSensitive ? a.equals(b) : a.equalsIgnoreCase(b);
+ }
+}