{@link com.intellij.util.xml.DomElement} interface is used to represent Schema- or DTD-based XML trees. It is more consistent, than the standard XML PSI tree. The concrete code dealing with XML is generated at runtime, based on your interfaces structure. For every needed XML type one should create subinterface of DomElement. This subinterface may have XML methods, that are used for getting children of tag, corresponding to current instance of the interface. Methods (getters and setters) may have the following annotations:

  • @{@link com.intellij.util.xml.TagValue} - method will deal (get or set) with tag text contents.
  • @{@link com.intellij.util.xml.Attribute} - gets attribute value. Attribute name is specified in "value" property.
  • @{@link com.intellij.util.xml.SubTag} - method (getter only) will deal with subtag. Should return instance of DomElement (the child DomElement type is inferred from return type of method). The subtag name is specified in "value" property. If there are several (fixed count) of same-named subtags, "index" property can specify, which subtag value should be returned. Sometimes the tag's existence is itself a value (a boolean one), then set property "indicator" to "true" (cannot be used with "index")
  • @{@link com.intellij.util.xml.SubTagList} - method will deal with subtag collection. Should return Collection of DomElements. The subtag name is specified in "value" property. The resulting Collection is immutable. There can be no setters annotated with it. Instead of them one may have "addition" methods: "MyDomElement addCollectionElement()". These addition methods may have "index" argument, specifying, where in collection to insert. One may not have one subtag name for both fixed-count children and collections.
  • @{@link com.intellij.util.xml.SubTagsList} - If you have several @{@link com.intellij.util.xml.SubTagList} collections and you need to access them all at once, this annotation will help. "value" property will hold the array of possible subtag names. One should have different addition methods for each subtag name, each returning its own DomElement type, each may have an "index" parameter. The element will be inserted in proper place in the "merged" collection, allowing you to mix elements of different types (if Schema or DTD allows).
  • One may annotate not every method, then the corresponding property classes and values are inferred from the method name, method return type and parameter types. For non-indicator subtag values with index 0 it's "SomeType getSomeName()", for collections - "{@link java.util.Collection}<SomeType> getSomeNames()" and "SomeType addSomeName()". (SomeType should extend {@link com.intellij.util.xml.DomElement}). For tag value the default methods are "getValue" and "setValue". The name is inferred using {@link com.intellij.util.xml.DomNameStrategy} subclasses. The default is {@link com.intellij.util.xml.HyphenNameStrategy}, which splits the camelhump name and joins the resulting words with "-". Another standard strategy is {@link com.intellij.util.xml.JavaNameStrategy}, that preserves the camel humps. Name strategy can be specified by @{@link com.intellij.util.xml.NameStrategy} annotation.

    {@link com.intellij.util.xml.DomElement}'s may have implementation for some methods, that are not directly connected with XML structure. An implementation class should be abstract class implementing this interface with only needed methods. Implementation classes can be specified via @{@link com.intellij.util.xml.Implementation} annotation, or in {@link com.intellij.util.xml.DomFileDescription}.

    DomElement's are created in {@link com.intellij.util.xml.DomManager}. One should register {@link com.intellij.util.xml.DomFileDescription} in {@link com.intellij.util.xml.DomManager} and provide root tag name and root {@link com.intellij.util.xml.DomElement} class. Also one can create mock DOM elements ({@link com.intellij.util.xml.DomManager#createMockElement(Class, com.intellij.openapi.module.Module, boolean)}, that are not connected with any disk XML file. One can copy contents from one DOM element to another using {@link com.intellij.util.xml.DomElement#copyFrom(com.intellij.util.xml.DomElement)} method.

    {@link com.intellij.util.xml.DomElementVisitor} subclasses can have methods like "visitTypeName(TypeName element)" where TypeName is some {@link com.intellij.util.xml.DomElement} subclass. Then such methods will be called in {@link com.intellij.util.xml.DomElement#accept(com.intellij.util.xml.DomElementVisitor)}.

    There's some kind of reflection, getting information about supported fixed and collection children. It's obtained via {@link com.intellij.util.xml.DomManager#getGenericInfo(java.lang.reflect.Type)} or {@link com.intellij.util.xml.DomElement#getGenericInfo()}.

    Standard way of representing children with tag value only is using {@link com.intellij.util.xml.GenericDomValue}<T>, which has method T getValue().

    If one has simple accessor method returning non-standard type, or GenericDomValue parameterized by non-standard type (standard types are {@link String}, {@link com.intellij.psi.PsiClass}, {@link com.intellij.psi.PsiType}, {@link Integer}, {@link Boolean}, enums), one should specify {@link com.intellij.util.xml.Converter} by @{@link com.intellij.util.xml.Convert} annotation near the method that gets this type or {@link com.intellij.util.xml.GenericDomValue}.

    See our Java EE and Weblogic models for examples.