DeleteTopElement (XmlDoc subroutine)
Delete top element from XmlDoc (XmlDoc class)
[Introduced in Sirius Mods 7.8]
This subroutine removes the top Element node from an XmlDoc, and it
makes the deleted Element's children be the "middle siblings" of its left and right siblings (Comments or PIs).
- The deleted Element may not have more than one Element child.
- The deleted Element may not have a Text child.
In common usage, the Element child of the deleted Element will become the new top Element of the XmlDoc.
Syntax
doc:DeleteTopElement
Syntax terms
doc | An XmlDoc object expression. |
---|
Usage notes
- DeleteTopElement is a convenient, better-performing alternative to using
AddSubtree to copy all but the top Element (or in multiple iterations, removing successive top Elements) from an XmlDoc.
For example, you can use it to remove the SOAP wrappers from an XmlDoc.
If the contents of
%xdoc
are:<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <data> ... </data> </soap:Body> </soap:Envelope>
Then the following User Language fragment:
%xdoc:DeleteTopElement %xdoc:DeleteTopElement
Results in the following contents of
%xdoc
:<data> ... </data>
- Using DeleteTopElement requires understanding how it handles
the occurrence of namespace declarations in the
XmlDoc. As shown in the “SOAP wrapper removal” example above,
DeleteTopElement will remove from the XmlDoc any namespace
declarations (in this example,
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
) that are not referenced after removing the top Element.Here is a variation of the above example that uses a default namespace declaration:
<Envelope xmlns"http://schemas.xmlsoap.org/soap/envelope/"> <Body> <data xmlns=""> ... </data> </Body> </Envelope>
Then the following User Language fragment:
%xdoc:DeleteTopElement %xdoc:DeleteTopElement
Results in the following contents of
%xdoc
:<data xmlns=""> ... </data>
As seen in this example, the null namespace declaration is not removed, even though, strictly speaking, it is not needed.
In addition, DeleteTopElement will move to the new top Element any namespace declarations that do continue to be referenced after the top Element deletion:
%n = %d:AddElement('foo', , 'u:uri') %n:AddElement('bar', , 'u:uri') %d:Print %d:DeleteTopElement Print 'After deletion:' %d:Print
The result of the above User Language fragment is:
<foo xmlns="u:uri"> <bar/> </foo> After deletion: <bar xmlns="u:uri"/>
- The performance of
DeleteTopElement should always be significantly better than an
approach using AddSubtree,
and in many cases, it is constant, regardless of the
size of the XmlDoc.
For a detailed explanation of when the cost of DeleteTopElement
might vary with the size of the XmlDoc,
consider the three reasons that the descendants
of the new top Element need to be recursively visited:
- Fixing references to the moved namespace declaration
As mentioned above, one or more namespace declarations can be moved from the deleted element to the new top element. Having done that, any references to the moved namespace must be fixed. A count is kept to the total references to moved namespace declarations; when this goes to zero, there is no further need to do this. So, for example:
<p:oldTop xmlns:p="p:uri"> <p:newTop> <child/> </p:newTop> </p:oldTop>
Thep:newTop
element needs to have its namespace reference fixed, but that is the only reference to it, so there is no need to visitchild
. - Fixing pointers to a deleted namespace declaration
When a namespace declaration is deleted, it may be pointed to by other namespace declarations (there is a graph of them in the XmlDoc). These pointers need to be fixed to point to the first non-deleted declaration following the deleted one. This is not needed by the descendants of any element that has a namespace declaration (in the original XmlDoc). So, for example:
<p:oldTop xmlns:p="p:uri"> <newTop> <q:child xmlns:q="q:uri"> <grandchild/> </q:child> </newTop> </p:oldTop>
BothnewTop
andq:child
need to have their namespace pointers fixed, but sinceq:child
has a namespace declaration,grandchild
doesn't need to be fixed, so it does not need to be visited. - Turning off “ancestor may have non-null default namespace
declaration”
In order to make certain namespace operations faster, there is a "state" maintained at XmlDoc nodes that permits a non-null default namespace declaration to occur on an ancestor. This state is fixed up if DeleteTopElement deletes a non-null namespace declaration (as happens in the second “SOAP wrapper removal” example above). The need to set this state is eliminated in descendants of an Element that have a default namespace declaration (either null or not). So, for example:
<oldTop xmlns="p:uri"> <newTop> <q:child xmlns="q:uri"> <grandchild/> </q:child> </newTop> </p:oldTop>
The state needs to be fixed at
newTop
, but sinceq:child
has a default namespace declaration, the state atgrandchild
does not need to be fixed up, so it does not need to be visited.
- Fixing references to the moved namespace declaration