DOM <=> PSI

Hi all,

I'm new to writing Intellij plugins, and I was wondering if there's any advice on how to convert a PsiElement into a DOM element?

My use case is:

- I already have the interfaces which extend 'com.intellij.util.xml.DomElement'
- I have a PsiElement (from an XML Document) which is given to me from extending GotoDeclarationHandlerBase (below)

  public abstract class GotoDeclarationHandlerBase implements GotoDeclarationHandler {
       @Nullable
       public abstract PsiElement getGotoDeclarationTarget(PsiElement sourceElement, Editor editor);

How do I go about converting this PSI element to a DomElement?

I noticed this is as a TODO on the DOM documentation page that i've been following religiously http://confluence.jetbrains.com/display/IDEADEV/Accessing+XML+through+IntelliJ+IDEA+DOM

Any advice would be much appreciated
Thanks

4 comments

What are you trying to achieve? Normally, if you want to add an extra reference to an XML element, you need to use PsiReferenceContributor to inject it, rather than override the "goto declaration" action. This will allow you to also support Find Usages and Rename for your reference.

0

Hi Dmitry, thanks for your response!

I'm trying to write a plugin that will allow me to jump from uses of a bean to the bean definition, or to a class method

Here is an example of the XML file :

<?xml version="1.0" encoding="UTF-8"?>
<blueprint
        xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">

    <!--
        Define a custom bean that can be referenced throughout the camel context object
    -->
    <bean id="customBeanId" class="me.example.CustomBean" />

    <camelContext xmlns="http://camel.apache.org/schema/blueprint">

        <route>
            <from uri="activemq:foo"/>
            <!-- This links to the bean defined above
                So it should go to the bean when ctrl+click ID, and the method when ctrl+click method -->
            <bean ref="customBeanId" method="someCustomMethod" />

            <!-- There is another way of referencing a bean,
                IE, this should also link to the custom bean when ctrl+clicked etc -->
            <setHeader headerName="foo">
                <method bean="customBeanId" method="otherCustomMethod" />
            </setHeader>

            <to uri="bean:customBeanId?method=someCustomMethod" />

        </route>
    </camelContext>
</blueprint>


I think I will need a lot of DOM interaction in order to do this?

Another problem is, there are multiple places that bean references can be made, for instance - so I need a way to easily convert a string to a more usable element if possible?

            <!-- Ctrl+click support for name + method as before -->
            <to uri="bean:customBeanId?method=someCustomMethod" />


Is there a preferred way to do this sort of manipulation+searching?
Currently I am working with DomElements and following the Custom  language tutorial very closely, but as there is no DOM manipulation in  that tutorial, I am doing a lot of research!

This is a quick example of the GotoDeclarationHandler i have at the minute

    // Handles the goto for the method attribute for the following
    // <bean ref="id" method="FOO" />
    public PsiElement getGotoDeclarationTarget(PsiElement sourceElement, Editor editor) {
        // Get the parent element, IE the methodAttributeValue
        final PsiElement parent = sourceElement.getParent();
        if (parent == null) { return null; }

        boolean isMethodPattern =
                xmlAttributeValue(
                        xmlAttribute("method").withSuperParent(1, xmlTag().withLocalName("bean"))
                ).accepts(parent);

        if(isMethodPattern) {
            // Get the parent xml tag, in order to get the id
            XmlAttributeValue methodAttributeValue = (XmlAttributeValue) parent;
            XmlAttribute xmlAttribute = (XmlAttribute) methodAttributeValue.getParent();
            XmlTag xmlTag = xmlAttribute.getParent();
            // ... 

 

As you can see I'm doing a lot of things that the DOM documentation says i shouldn't be doing - so I would really prefer to be working with the DOMElements I have created instead! :)

For reference, this is the DomElement interface I am using for the Bean declaration (The one defined outside of a camel context XML element)

    public interface Bean extends DomElement {
        // TODO - What does @NameValue do?
        @Attribute("id")
        GenericAttributeValue<String> getId();

        @Attribute("class")
        @NotNull
        GenericAttributeValue<PsiClass> getClassAttribute();
    }


So am thinking I need to a way to perform PSI => DOM if possible, am I right in thinking this?
Thank you in advance for your time! :)

0

You don't need GotoDeclarationHandler at all, please disable it first to avoid any interference.

In your DOM-class for "<bean>" element define attribute "id" with @NameValue, then "ref" should return GenericAttributeValue<YourBeanClass> and resolving should work out of the box. For non DOM<->DOM references you can use com.intellij.util.xml.CustomReferenceConverter to create your own PsiReferences.

0

Thank you; I didn't realise that the registered File description would handle all of this for me out of the box!
I had imagined that I would need to do all of this myself, similiar to the Custom Language example that was recently released.

Thanks again.

0

Please sign in to leave a comment.