package org.intellij.plugins.xsltDebugger.rt.engine.local.xalan; import org.apache.xalan.templates.ElemLiteralResult; import org.apache.xalan.templates.ElemParam; import org.apache.xalan.templates.ElemTemplateElement; import org.apache.xalan.templates.ElemVariable; import org.apache.xalan.trace.TracerEvent; import org.apache.xalan.transformer.TransformerImpl; import org.apache.xml.dtm.DTM; import org.apache.xml.dtm.DTMIterator; import org.apache.xml.dtm.ref.DTMNodeProxy; import org.apache.xml.utils.PrefixResolver; import org.apache.xml.utils.PrefixResolverDefault; import org.apache.xpath.XPath; import org.apache.xpath.XPathContext; import org.intellij.plugins.xsltDebugger.rt.engine.Debugger; import org.intellij.plugins.xsltDebugger.rt.engine.Value; import org.intellij.plugins.xsltDebugger.rt.engine.local.AbstractFrame; import org.intellij.plugins.xsltDebugger.rt.engine.local.VariableComparator; import org.intellij.plugins.xsltDebugger.rt.engine.local.VariableImpl; import org.w3c.dom.Node; import javax.xml.transform.TransformerException; import java.util.*; class XalanStyleFrame extends AbstractFrame<Debugger.StyleFrame> implements Debugger.StyleFrame { private final boolean myWithSourceFrame; private final TransformerImpl myTransformer; private final ElemTemplateElement myCurrentElement; private final XPathContext myContext; private final int myCurrentNode; private final int myLineNumber; private final String myURI; private final String myInstr; public XalanStyleFrame(TracerEvent ev, Debugger.StyleFrame currentFrame, boolean withSourceFrame) { super(currentFrame); myWithSourceFrame = withSourceFrame; myInstr = getInstruction(ev.m_styleNode); myLineNumber = ev.m_styleNode.getLineNumber(); if (ev.m_styleNode.getSystemId() != null) { myURI = ev.m_styleNode.getSystemId(); } else if (currentFrame != null && currentFrame.getURI() != null) { myURI = currentFrame.getURI(); } else { myURI = ev.m_processor.getStylesheet().getSystemId(); } myTransformer = ev.m_processor; myCurrentElement = myTransformer.getCurrentElement(); myContext = ev.m_processor.getXPathContext(); myCurrentNode = myContext.getCurrentNode(); } private void addVariable(ElemVariable variable, boolean global, Collection<Debugger.Variable> variables) { final Debugger.Variable.Kind kind = variable instanceof ElemParam ? Debugger.Variable.Kind.PARAMETER : Debugger.Variable.Kind.VARIABLE; assert global == variable.getIsTopLevel() : global + " vs. " + variable.getIsTopLevel() + " (" + variable.getName() + ")"; final String name = variable.getName().getLocalName(); try { final Value value = kind == Debugger.Variable.Kind.PARAMETER ? eval("$" + variable.getName().toString()) : // http://youtrack.jetbrains.net/issue/IDEA-78638 new XObjectValue(variable.getValue(myTransformer, myCurrentNode)); variables.add(new VariableImpl(name, value, global, kind, variable.getSystemId(), variable.getLineNumber())); } catch (TransformerException e) { debug(e); } catch (Debugger.EvaluationException e) { debug(e); } } public boolean isWithSourceFrame() { return myWithSourceFrame; } public String getInstruction() { return myInstr; } public List<Debugger.Variable> getVariables() { assert isValid(); return collectVariables(); } private List<Debugger.Variable> collectVariables() { final Set<Debugger.Variable> variables = new HashSet<Debugger.Variable>(); ElemTemplateElement p = myCurrentElement; while (p != null) { ElemTemplateElement s = p; while ((s = s.getPreviousSiblingElem()) != null) { if (s instanceof ElemVariable) { final ElemVariable variable = (ElemVariable)s; if (variable.getIsTopLevel()) { continue; } addVariable(variable, false, variables); } } p = p.getParentElem(); } @SuppressWarnings({"unchecked", "UseOfObsoleteCollectionType"}) final Vector<ElemVariable> globals = myTransformer.getStylesheet().getVariablesAndParamsComposed(); for (ElemVariable variable : globals) { addVariable(variable, true, variables); } final ArrayList<Debugger.Variable> result = new ArrayList<Debugger.Variable>(variables); Collections.sort(result, VariableComparator.INSTANCE); return result; } public String getURI() { return myURI; } public int getLineNumber() { return myLineNumber; } public Value eval(String expr) throws Debugger.EvaluationException { assert isValid(); try { final DTMIterator context = myTransformer.getContextNodeList(); final int ctx; final DTM dtm = context.getDTM(myCurrentNode); if (dtm.getDocumentRoot(myCurrentNode) == myCurrentNode) { ctx = dtm.getFirstChild(myCurrentNode); } else { ctx = myCurrentNode; } final DTMNodeProxy c = new DTMNodeProxy(dtm, ctx); final PrefixResolver prefixResolver = new PrefixResolverDefault(c) { public String getNamespaceForPrefix(String prefix, Node context) { if (context instanceof DTMNodeProxy) { final DTMNodeProxy proxy = (DTMNodeProxy)context; final DTM dtm = proxy.getDTM(); int p = proxy.getDTMNodeNumber(); while (p != DTM.NULL) { int nsNode = dtm.getFirstNamespaceNode(p, true); while (nsNode != DTM.NULL) { final String s = dtm.getLocalName(nsNode); if (s.equals(prefix)) { return dtm.getNodeValue(nsNode); } nsNode = dtm.getNextNamespaceNode(p, nsNode, true); } p = dtm.getParent(p); } } return super.getNamespaceForPrefix(prefix, context); } }; final XPath xPath = new XPath(expr, myCurrentElement, prefixResolver, XPath.SELECT, myTransformer.getErrorListener()); return new XObjectValue(xPath.execute(myContext, myCurrentNode, myCurrentElement)); } catch (Exception e) { debug(e); final String message = e.getMessage(); throw new Debugger.EvaluationException(message != null ? message : e.getClass().getSimpleName()); } } static String getInstruction(ElemTemplateElement node) { final String name = node.getNodeName(); if (node instanceof ElemLiteralResult) { return name; } else if (name != null && name.indexOf(':') == -1) { return "xsl:" + name; } return name; } }