DeleteTopElement (XmlDoc subroutine)

From m204wiki
Revision as of 17:24, 3 March 2014 by JAL (talk | contribs)
Jump to navigation Jump to search

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:
    1. 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>

      The p:newTop element needs to have its namespace reference fixed, but that is the only reference to it, so there is no need to visit child.
    2. 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>

      Both newTop and q:child need to have their namespace pointers fixed, but since q:child has a namespace declaration, grandchild doesn't need to be fixed, so it does not need to be visited.
    3. 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 since q:child has a default namespace declaration, the state at grandchild does not need to be fixed up, so it does not need to be visited.

See also