DeleteTopElement (XmlDoc subroutine): Difference between revisions
mNo edit summary |
mNo edit summary |
||
Line 2: | Line 2: | ||
This subroutine removes the top <var>Element</var> from an <var>XmlDoc</var>, and it | This subroutine removes the top <var>Element</var> from an <var>XmlDoc</var>, and it | ||
makes | makes the deleted <var>Element</var>'s children be the “middle siblings” of its left and right siblings (<var>Comments</var> or <var>PIs</var>). | ||
<ul> | <ul> | ||
<li>The deleted | <li>The deleted <var>Element</var> may not have more than one | ||
<var>Element</var> child. | <var>Element</var> child. | ||
<li>The deleted | <li>The deleted <var>Element</var> may not have a <var>Text</var> child. | ||
</ul> | </ul> | ||
In common usage, the <var>Element</var> child of the deleted <var>Element</var> will become the | In common usage, the <var>Element</var> child of the deleted <var>Element</var> will become the | ||
new top <var>Element</var> of the <var>XmlDoc</var>. | new top <var>Element</var> of the <var>XmlDoc</var>. | ||
__TOC__ | |||
==Syntax== | ==Syntax== | ||
Line 24: | Line 24: | ||
<ul> | <ul> | ||
<li><var>DeleteTopElement</var> is a convenient, better-performing alternative to using | <li><var>DeleteTopElement</var> is a convenient, better-performing alternative to using | ||
<var>[[AddSubtree (XmlDoc/XmlNode function)|AddSubtree]]</var> to copy all but the top Element (or in multiple iterations, | <var>[[AddSubtree (XmlDoc/XmlNode function)|AddSubtree]]</var> to copy all but the top <var>Element</var> (or in multiple iterations, removing successive top <var>Elements</var>) from an <var>XmlDoc</var>. | ||
removing successive top Elements) from an <var>XmlDoc</var>. | |||
For example, you can use it to remove the SOAP wrappers from an <var>XmlDoc</var>. | For example, you can use it to remove the SOAP wrappers from an <var>XmlDoc</var>. | ||
Line 46: | Line 45: | ||
</data> | </data> | ||
</nowiki></p> | </nowiki></p> | ||
<li> | <div id="wrap2"></div> | ||
<li>Using <var>DeleteTopElement</var> requires understanding how it handles | |||
<var>XmlDoc</var> | the occurrence of namespace declarations in the | ||
<var>XmlDoc</var>. As shown in the “SOAP wrapper removal” example above, | |||
As shown in the “SOAP wrapper removal” example above, | |||
<var>DeleteTopElement</var> will remove from the <var>XmlDoc</var> any namespace | <var>DeleteTopElement</var> will remove from the <var>XmlDoc</var> any namespace | ||
declarations (in this example, <code>xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"</code>) | declarations (in this example, <code>xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"</code>) | ||
that '''are not''' referenced after removing the top Element. | that '''are not''' referenced after removing the top <var>Element</var>. | ||
<p>Here is a variation of the above example that uses a | |||
default namespace declaration:</p> | default namespace declaration:</p> | ||
<p class="code"><nowiki><Envelope xmlns"http://schemas.xmlsoap.org/soap/envelope/"> | <p class="code"><nowiki><Envelope xmlns"http://schemas.xmlsoap.org/soap/envelope/"> | ||
Line 80: | Line 76: | ||
removed, even though, strictly speaking, it is not needed. | removed, even though, strictly speaking, it is not needed. | ||
In addition, <var>DeleteTopElement</var> will move to the new top Element | In addition, <var>DeleteTopElement</var> will move to the new top <var>Element</var> | ||
any namespace declarations that '''do''' continue to be | any namespace declarations that '''do''' continue to be | ||
referenced after the top Element deletion: | referenced after the top <var>Element</var> deletion: | ||
<p class="code" | <p class="code">%n = %d:AddElement('foo', , 'u:uri') | ||
%n:AddElement('bar', , 'u:uri') | %n:AddElement('bar', , 'u:uri') | ||
%d:Print | %d:Print | ||
Line 89: | Line 85: | ||
Print 'After deletion:' | Print 'After deletion:' | ||
%d:Print | %d:Print | ||
</p> | |||
The result of the above <var class="product">User Language</var> fragment is: | The result of the above <var class="product">User Language</var> fragment is: | ||
<p class="output"><nowiki><foo xmlns="u:uri"> | <p class="output"><nowiki><foo xmlns="u:uri"> | ||
Line 105: | Line 101: | ||
For a detailed explanation of when the cost of <var>DeleteTopElement</var> | For a detailed explanation of when the cost of <var>DeleteTopElement</var> | ||
might vary with the size of the <var>XmlDoc</var>, | might vary with the size of the <var>XmlDoc</var>, | ||
consider the three reasons that the descendants | |||
of the new top Element need to be recursively visited: | of the new top <var>Element</var> need to be recursively visited: | ||
<ol> | <ol> | ||
<li>Fixing references to moved namespace declaration | <li>Fixing references to the moved namespace declaration | ||
<p> | <p> | ||
As mentioned above, one or more namespace declarations can be moved | As mentioned above, one or more namespace declarations can be moved | ||
Line 114: | Line 110: | ||
Having done that, any references to the moved namespace must be fixed. | Having done that, any references to the moved namespace must be fixed. | ||
A count is kept to the total references to moved namespace | A count is kept to the total references to moved namespace | ||
declarations; when this goes to zero, there is no | declarations; when this goes to zero, there is no further need to do this. | ||
So, for example:</p> | So, for example:</p> | ||
<p class="code"><nowiki><p:oldTop xmlns:p="p:uri"> | <p class="code"><nowiki><p:oldTop xmlns:p="p:uri"> | ||
Line 122: | Line 118: | ||
</p:oldTop> | </p:oldTop> | ||
</nowiki></p> | </nowiki></p> | ||
The <code>p:newTop</code> element needs to have | The <code>p:newTop</code> element needs to have its namespace reference fixed, but that is the only reference to it, so there is no need to visit <code>child</code>.</li> | ||
<li>Fixing pointers to a deleted namespace declaration | <li>Fixing pointers to a deleted namespace declaration | ||
<p> | <p> | ||
When a namespace declaration is deleted, it may be pointed to by other | When a namespace declaration is deleted, it may be pointed to by other | ||
namespace declarations (there is a graph of them in the <var>XmlDoc</var>) | namespace declarations (there is a graph of them in the <var>XmlDoc</var>). These | ||
pointers need to be fixed to point to the first non-deleted | pointers need to be fixed to point to the first non-deleted | ||
declaration following the deleted one. | declaration following the deleted one. | ||
Line 148: | Line 144: | ||
namespace declaration to occur on an ancestor. | namespace declaration to occur on an ancestor. | ||
This state is fixed up if <var>DeleteTopElement</var> deletes a non-null | This state is fixed up if <var>DeleteTopElement</var> deletes a non-null | ||
namespace declaration (as happens in the second “SOAP wrapper | namespace declaration (as happens in the [[#wrap2|second “SOAP wrapper | ||
removal” example above | removal” example]] above). | ||
The need to set this state is eliminated in descendants of an Element | The need to set this state is eliminated in descendants of an <var>Element</var> | ||
that have a default namespace declaration (either null or not). | that have a default namespace declaration (either null or not). | ||
So, for example:</p> | So, for example:</p> |
Revision as of 19:26, 3 June 2011
Delete top element from XmlDoc (XmlDoc class)
[Introduced in Sirius Mods 7.8]
This subroutine removes the top Element 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