Manipulating the Tree
The XML PSI tree doesn)'t provide many strongly typed methods for manipulating the tree. The IXmlTag
and IXmlTagContainer
nodes are the only ones that provide methods.
Both interfaces allow adding an attribute or a tag, specifying an anchor
tree node that should be used to insert before or after. This anchor
node can be null, in which case, the *After
methods will add the new attribute or tag before all other nodes, and the *Before
methods will add it after the other nodes.
Util classes
While the tree nodes don't provide any more methods for manipulating the tree, the Util classes do. Specifically, XmlAttributeUtil
and XmlTagUtil
.
The XmlAttributeUtil.SetValue
method sets the value of the attribute to the string passed in. Since there are no methods for manipulating the text of the attribute value, it does this by replacing the IXmlAttributeValue
node in the given attribute with a new instance.
The XmlTagUtil
methods rewrite the tree, replacing a tag with an opening and closing element to one which is self-closing, and vice versa.
Removing nodes
While IXmlTag.RemoveAttribute
allows for removing an attribute, there isn't a method for removing a child tag, or other nodes, such as processing instructions. In this case, ModificationUtil.DeleteChild
can be used to remove a specific node, or ModificationUtil.DeleteChildRange
to remove a range of nodes.
Adding nodes
Adding a new node is fairly straightforward, in that it's a simple call to one of the ModificationUtil.AddChild*
methods.
Before adding a node, however, it must be created first. The XML PSI has a couple of methods for creating nodes. The XmlElementFactory
class can create an instance of IXmlFile
, and has methods for creating tags and attributes. It does not provide methods for creating other tree node types. You can use the XmlElementFactory.GetInstance
method to get an instance of the element factory, passing in an existing ITreeNode
for context.
The IXmlElementFactory
interface provides more fine-grained methods for creating XML tree nodes (note that XmlElementFactory
does not implement IXmlElementFactory
). This interface is implemented per-language, for each XML-derived language (such as web.config, build scripts, etc). The default implementation is XmlTreeNodeFactory
. The XmlTreeNodeFactory.GetInstance
static methods will get the appropriate language specific implementation.
See the documentation on element factories for more details.
Modifying nodes
Unless a tree node or utility class provides a helper method for manipulating the tree node, then any time the content of the XML tree needs to be updated, then the node containing that content must be replaced. That is, a new node is created, and replaces the old node in the tree.
This can be quite complex, depending on what exactly needs to be replaced. The XmlElementFactory
class provides methods to easily create tags and attributes, but not for creating other node types. The language specific implementations of IXmlElementFactory
can create all of the other node types, but usually requires more work to build the tree nodes required.
For example, replacing the inner text of a tag is complicated by the text being represented by both text token nodes and whitespace token nodes. Replacing a single word is therefore straightforward:
However, replacing content that spans whitespace nodes is more involved. A better approach here can be to create a new tag with the entire expected text content, and replace the child nodes of the original tag with the new tag's children. Alternatively, replace the whole tag with the newly created one (ensuring attributes are correctly copied across).