PsiReferenceProvider doesn't work with Well Formed XML files
I implemented PsiReferenceProvider to navigate across XML files, but it works only if there is no correct declaration (correct !DOCTYPE) , though MyPsiReferenceProvider is triggered when I open the XML file even when I press CTRL + B it triggers PsiReferenceBase implementation. It calls methods like multiResolve() and resolve()
MyXmlReference extends PsiReferenceBase<PsiElement> implements PsiPolyVariantReference
the correct XML declaration is known as "Well Formed" XML
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE business PUBLIC "//Kas//DTD Business Data/" "busienss.dtd"> <business>
<WORK .../>
</business>
Same if XML definition looks like this (doesn't work)
<?xml version='1.0' encoding='UTF-8'?> <business>
<WORK .../>
</business>
But, if XML looks like this
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE business "busienss.dtd"> <business>
the implementation of PsiReferenceProvider works as it was with correct XML declaration but in this case, it displays Usages.
How to make it works properly without touching the XML declaration, or without DOCTYPE tag as in the second example?
Please sign in to leave a comment.
Please try registering your provider with com.intellij.psi.PsiReferenceRegistrar#HIGHER_PRIORITY
No, it doesn't help, I tried HIGHER_PRIORITY and even 1000.0, it doesn't work when XML has no well-formed declaration
Sorry for delay. Could you please post full code of your com.intellij.psi.PsiReferenceRegistrar#registerReferenceProvider(com.intellij.patterns.ElementPattern<T>, com.intellij.psi.PsiReferenceProvider, double) implementation? Thanks.
Here you are
Could you please clarify the *_PATTERN you use? It seems you're creating reference on the XmlAttribute, but not the XmlAttributeValue, is that intended?
companion object {
private const val DEBUG_METHOD_NAME = "withName"
private val DATASET_CONDITION = XmlPatterns.xmlTag().with(object : PatternCondition<XmlTag?>(DEBUG_METHOD_NAME) {
override fun accepts(xmlTag: XmlTag, context: ProcessingContext): Boolean {
return true
}
}).withParent(XmlPatterns.xmlTag().withName(DATASET_ROOT_TAG))
private val ID_PATTERN = XmlPatterns.xmlAttribute().withName(ID_ATTRIBUTE).withParent(DATASET_CONDITION)
private val ENTITY_PATTERN = XmlPatterns.xmlTag().withAnyAttribute(ID_ATTRIBUTE).withParent(XmlPatterns.xmlTag().withName(DATASET_ROOT_TAG))
private val FOREIGN_KEY_PATTERN = XmlPatterns.xmlAttribute().with(object : PatternCondition<XmlAttribute?>(DEBUG_METHOD_NAME) {
override fun accepts(xmlAttribute: XmlAttribute, context: ProcessingContext): Boolean {
return xmlAttribute.name.endsWith(ID_POSTFIX)
}
}).withParent(DATASET_CONDITION)
private val ID_REFERENCE_CONTRIBUTOR = IdPsiReferenceProvider()
private val ENTITY_REFERENCE_CONTRIBUTOR = EntityAttributePsiReferenceProvider()
private val FOREIGN_KEY_REFERENCE_CONTRIBUTOR = ForeignKeyPsiReferenceProvider()
}
Here you are
It seems what you actually want to build is installing references on the "id" XML attribute, so you must register the reference on the XmlAttributeValue of "id" attribute, not on the parent containing XmlTag.
The pattern would look something like this:
XmlPatterns.xmlAttributeValue().withLocalName("id").withSuperParent(2, XmlPatterns.xmlTag().withLocalName("tagName").withNamespace("Your XML namespace ID"))
Depending on your plugin's usecase, also consider using XML DOM Api instead of low-level XML access https://plugins.jetbrains.com/docs/intellij/xml-dom-api.html