|
|
(13 intermediate revisions by 4 users not shown) |
Line 1: |
Line 1: |
| {{Hierarchy header}}
| | Content moved to M204Int, but history preserved here. |
|
| |
| The following sections describe changes in the <var class="product">[[Janus SOAP]]</var> [[XmlDoc API]] in this release.
| |
| ==XPathError exceptions==
| |
| All <var>XmlDoc</var> and <var>XmlNode</var> class methods that accept XPath arguments
| |
| now can throw an [[#The XPathError exception class|XPathError exception]].
| |
|
| |
| An example of using the <var>XPathError</var> exception is:
| |
| <p class="code"><nowiki>%err Object XPathError
| |
| Try
| |
| %d:Print('a b c')
| |
| Catch XPathError To %err
| |
| PrintText {~} = {%err:Reason}
| |
| PrintText {~} = {%err:Description}
| |
| PrintText {~} = {%err:CharacterPosition}
| |
| End Try
| |
| </nowiki></p>
| |
| Since the expression in the above invocation of the <var>Print</var> method
| |
| (<code>a b c</code>) is not a valid XPath expression, the above fragment
| |
| will result in the following:
| |
| <p class="code"><nowiki>%err:Reason = SyntaxError
| |
| %err:Description = Expect "/" for new step or "[" for predicate
| |
| %err:CharacterPosition = 3
| |
| </nowiki></p>
| |
|
| |
| The methods in the <var>XmlDoc</var> and <var>XmlNode</var> classes that can throw an
| |
| <var>XPathError</var> exception are:
| |
| <ul>
| |
| <li><var>Audit</var>
| |
| <li><var>DefaultURI</var>
| |
| <li><var>DeleteSubtree</var>
| |
| <li><var>Exists</var>
| |
| <li><var>Length</var>
| |
| <li><var>LocalName</var>
| |
| <li><var>Prefix</var>
| |
| <li><var>PrefixURI</var>
| |
| <li><var>Print</var>
| |
| <li><var>Qname</var>
| |
| <li><var>SelectCount</var>
| |
| <li><var>SelectNodes</var>
| |
| <li><var>SelectSingleNode</var>
| |
| <li><var>Serial</var>
| |
| <li><var>ToXpathStringlist</var>
| |
| <li><var>Trace</var>
| |
| <li><var>Type</var>
| |
| <li><var>UnionSelected</var>
| |
| <li><var>Uri</var>
| |
| <li><var>Value</var>
| |
| <li><var>ValueDefault</var>
| |
| <li><var>XPathNodeID</var>
| |
| </ul>
| |
| ===The XPathError exception class===
| |
| The members of the <var>XPathError</var> exception class are described below.
| |
| Except for the constructor, <var>New</var>, all class members are
| |
| <var>[[Methods#Method definition syntax|ReadOnly]]</var> properties:
| |
| <table>
| |
| <tr><th>Reason
| |
| </th><td>An enumeration of type <var>XmlPathErrorReason</var>. The possible values are: <table> <tr><th>SyntaxError </th><td>A violation of the syntax of an XPath expression. </td></tr> <tr><th>EmptyResult </th><td>There are no nodes matched by the XPath expression, and the method requires at least one matching node. </td></tr></table>
| |
| </td></tr>
| |
| <tr><th>CharacterPosition
| |
| </th><td>The position within the XPath expression at or before which the error was detected.
| |
| </td></tr>
| |
| <tr><th>Description
| |
| </th><td>A message that explains the error.
| |
| </td></tr>
| |
| <tr><th>New
| |
| </th><td>The constructor for the class, <var>New</var> lets you set values for each member of the class.
| |
| <p class="code"><nowiki>%ex = New ( Reason = reasonEnum -
| |
| [, CharacterPosition = num] -
| |
| [, Description = string] )
| |
| </nowiki></p>
| |
| The <var>Reason</var> argument is required. All other arguments are optional,
| |
| [[Methods#Named parameters|NameRequired]], and have default values of the null string or 0 as appropriate.
| |
| </td></tr></table>
| |
| ==NewFromRecord shared function in XmlDoc class==
| |
| This shared function creates a new <var>XmlDoc</var> object which contains the fields and
| |
| fieldgroups from the current record.
| |
| This record extraction is the
| |
| same operation that is performed by the [[#LoadFromRecord subroutine in XmlDoc and XmlNode classes|LoadFromRecord subroutine]] and by the [[ToXmlDoc (Record function)|ToXmlDoc function]] in the [[Record class]].
| |
|
| |
| Whether to use <var>ToXmlDoc</var>, <var>NewFromRecord</var>, or <var>LoadFromRecord</var> depends on what is
| |
| most convenient for your application.
| |
| If you are already using a <var>Record</var> object which references the desired record,
| |
| using <var>ToXmlDoc</var> may be more convenient; if not, then either
| |
| <var>NewFromRecord</var> or <var>LoadFromRecord</var> (both of which require that the method be
| |
| contained in a “record loop”) may be more convenient.
| |
| You must use <var>LoadFromRecord</var> if you want to add the record's content as a
| |
| subtree to a non-empty <var>XmlDoc</var>;
| |
| in other cases the <var>NewFromRecord</var> “factory method” may be your choice.
| |
|
| |
| Since <var>NewFromRecord</var> and <var>ToXmlDoc</var> create new <var>XmlDoc</var> objects, they have the
| |
| <var>AllowNull</var> argument for setting the created <var>XmlDoc</var>'s <var>AllowNull</var>
| |
| poperty; <var>LoadFromRecord</var> does not have the <var>AllowNull</var> argument.
| |
|
| |
| As stated, both
| |
| <var>NewFromRecord</var> and <var>LoadFromRecord</var> must be
| |
| contained in a “record loop”, for example, an <var>FRN</var> block, and they may not be
| |
| invoked within a fieldgroup context.
| |
|
| |
| Except for these considerations, <var>ToXmlDoc</var>, <var>NewFromRecord</var>, and <var>LoadFromRecord</var>
| |
| all perform the same operation and have the same arguments.
| |
| The discussion of the “extract from record to <var>XmlDoc</var>” operation,
| |
| generally uses <var>LoadFromRecord</var>, except where one of these considerations
| |
| is relevant to the discussion.
| |
|
| |
| The arguments to <var>NewFromRecord</var> are shown in this statement:
| |
| <p class="code"><nowiki>%newXmlDoc = %(XmlDoc):NewFromRecord( -
| |
| [AttributeValues=bool] -
| |
| [, AttributeNames=bool] -
| |
| [, NamesToLower=bool] -
| |
| [, AllowUnreversible=bool] -
| |
| [, CodepageTable=bool] -
| |
| [, AllowNull=bool] )
| |
| </nowiki></p>
| |
|
| |
| Descriptions of '''''some of the arguments''''' follow:
| |
|
| |
| <table>
| |
| <tr><th>%newXmlDoc</th>
| |
| <td><var>NewFromRecord</var> returns a new <var>XmlDoc</var> object.</td></tr>
| |
| <tr><th>%(XmlDoc)</th>
| |
| <td>The class name in parentheses denotes a shared method and is one way to invoke <var>NewFromRecord</var>. You can also use an object expression whose type is <var>XmlDoc</var> (even if the value of the expression is null).</td></tr>
| |
| <tr><th>AllowNull</th>
| |
| <td>The value of this [[Boolean]] argument, which defaults to <var>False</var>, is copied to the <var>AllowNull</var> property of the <var>XmlDoc</var> created by <var>NewFromRecord</var>.
| |
| The <var>XmlDoc</var>'s <var>AllowNull</var> property, in turn, determines whether
| |
| field values that contain the X'00' character are stored in the
| |
| <var>XmlDoc</var> with base64 encoding.
| |
| Such values are base64 encoded if <var>AllowNull</var> is <var>False</var>.
| |
|
| |
| A <var>False</var> value of the <var>AllowNull</var> property of an <var>XmlDoc</var> is its default.
| |
| This prevents null characters from being stored in the <var>XmlDoc</var>, so
| |
| it will be conformant to the XML Recommendation, which does
| |
| not allow null characters in an XML document.
| |
|
| |
| The following fragment:
| |
| <p class="code"><nowiki>%s = 'Field with null/' With '00':X With '/'
| |
| Store Record
| |
| FOO = %s
| |
| End Store
| |
| %r = $CurRec
| |
| FRN %r
| |
| %doc = %doc:NewFromRecord
| |
| End For
| |
| PrintText {~} = {%doc:AllowNull}
| |
| %doc:Print
| |
| </nowiki></p>
| |
|
| |
| produces this output:
| |
| <p class="output"><nowiki>%doc:AllowNull = False
| |
| <Record version="1" file="QAWORK" number="1">
| |
| <field name="FOO" encoding="base64">
| |
| xomFk4RApomjiECVpJOTYQBh
| |
| </field>
| |
| </Record>
| |
| </nowiki></p>
| |
|
| |
| In the above output, notice that <code>FOO</code> is base64 encoded,
| |
| because it contains a null character, and
| |
| null characters are not allowed in an <var>XmlDoc</var> whose <var>AllowNull</var>
| |
| property is <var>False</var>.
| |
| The following fragment:
| |
| <p class="code"><nowiki>%s = 'Field with null/' With '00':X With '/'
| |
| Store Record
| |
| FOO = %s
| |
| End Store
| |
| %r = $CurRec
| |
| FRN %r
| |
| %doc = %doc:NewFromRecord(AllowNull=True)
| |
| End For
| |
| PrintText {~} = {%doc:AllowNull}
| |
| %doc:Print
| |
| </nowiki></p>
| |
|
| |
| produces the following output:
| |
| <p class="output"><nowiki>%doc:AllowNull = True
| |
| <Record version="1" file="QAWORK" number="1">
| |
| <field name="FOO">
| |
| Field with null/&#x0;/
| |
| </field>
| |
| </Record>
| |
| </nowiki></p>
| |
|
| |
| In the above output, <code>FOO</code> is not base64 encoded; the <var>XmlDoc</var> contains
| |
| a null character, which is displayed by the <var>Print</var> method using a
| |
| character reference (<code>&#x0;</code>).
| |
| This may be useful for visually inspecting the contents of the
| |
| <var>XmlDoc</var>, again noting that such a document is not, strictly speaking,
| |
| conformant to the XML Recommendation.
| |
|
| |
| See the description of the <var>AttributeValue</var> argument of the [[#LoadFromRecord subroutine in XmlDoc and XmlNode classes|LoadFromRecord subroutine]] for a list of all conditions which force base64 encoding of the "field" element.</td></tr>
| |
| <tr><th>Other NewFromRecord arguments</th>
| |
| <td>See [[#LoadFromRecord subroutine in XmlDoc and XmlNode classes|LoadFromRecord]] for a discussion of all the other arguments of <var>NewFromRecord</var>.</td></tr>
| |
| </table>
| |
|
| |
| See the <var>[[#LoadFromRecord subroutine in XmlDoc and XmlNode classes|LoadFromRecord]]</var> section below for a discussion of extracting the contents of the current record into an <var>XmlDoc</var>.
| |
|
| |
| Note that this method was actually introduced in version 7.6 of
| |
| the <var class="product">Sirius Mods</var>, although the <var>AllowNull</var> argument was
| |
| not provided until version 7.7 of the <var class="product">Sirius Mods</var>.
| |
|
| |
| ==LoadFromRecord subroutine in XmlDoc and XmlNode classes==
| |
| This subroutine adds to an <var>XmlDoc</var> object a subtree that contains the fields and
| |
| fieldgroups from the current record.
| |
| This record extraction is the
| |
| same operation that is performed by the [[#NewFromRecord shared function in XmlDoc class|NewFromRecord
| |
| function]] and by the <var>[[ToXmlDoc (Record function)|ToXmlDoc]]</var> function in the <var>[[Record class|Record]]</var> class.
| |
|
| |
| Whether to use <var>ToXmlDoc</var>, <var>NewFromRecord</var>, or <var>LoadFromRecord</var> depends on what is
| |
| most convenient for your application.
| |
| If you are already using a <var>Record</var> object that references the desired record,
| |
| using <var>ToXmlDoc</var> may be more convenient; if not, then either
| |
| <var>NewFromRecord</var> or <var>LoadFromRecord</var> (both of which require that the method be
| |
| contained in a “record loop”) may be more convenient.
| |
| You must use <var>LoadFromRecord</var> if you want to add the record's content as a
| |
| subtree to a non-empty <var>XmlDoc</var>;
| |
| in other cases, the <var>NewFromRecord</var> “factory method” may be your choice.
| |
|
| |
| Since <var>NewFromRecord</var> and <var>ToXmlDoc</var> create new <var>XmlDoc</var> objects, they have the
| |
| <var>AllowNull</var> argument for setting the created <var>XmlDoc</var>'s <var>[[allowNull (XmlDoc property)|AllowNull]]</var>
| |
| property. <var>LoadFromRecord</var> does not have the <var>AllowNull</var> argument.
| |
|
| |
| As stated, both
| |
| <var>NewFromRecord</var> and <var>LoadFromRecord</var> must be
| |
| contained in a “record loop” (for example, an <var>FRN</var> block), and they may not be
| |
| invoked within a fieldgroup context.
| |
|
| |
| Except for these considerations, <var>ToXmlDoc</var>, <var>NewFromRecord</var>, and <var>LoadFromRecord</var>
| |
| all perform the same operation and have the same arguments.
| |
| The discussion of the “extract from record to <var>XmlDoc</var>” operation
| |
| generally uses <var>LoadFromRecord</var>, except where one of these considerations
| |
| is relevant to the discussion.
| |
|
| |
| The arguments to <var>LoadFromRecord</var> are shown in the following statement:
| |
| <p class="code"><nowiki>%xmlNr:LoadFromRecord( -
| |
| [AttributeValues=bool] -
| |
| [, AttributeNames=bool] -
| |
| [, NamesToLower=bool] -
| |
| [, AllowUnreversible=bool] -
| |
| [, CodepageTable=bool] )
| |
| </nowiki></p>
| |
|
| |
| Where:
| |
|
| |
| <table>
| |
| <tr><th>%xmlNr
| |
| </th><td>LoadFromRecord is in both the XmlDoc and XmlNode classes.
| |
|
| |
| When the method object is an XmlDoc, or refers to the Root node of an XmlDoc: <ul> <li>The XmlDoc must not contain any nodes except the Root node. <li>A 'Record' element is added as the top level element of the XmlDoc. Children are added to the 'Record' element, representing the outer fields and fieldgroups of the record. </ul>
| |
|
| |
| When the method object is an XmlNode not referring to the Root node: of an XmlDoc:
| |
| <ul>
| |
| <li>The node must be an Element node.
| |
| <li>Children are added to that element, representing the outer fields and fieldgroups of the record.
| |
| <li>See the [[#AddToRecord subroutine in XmlDoc class|AddToRecord subroutine]] for some examples of extracting multiple records into a single XmlDoc.
| |
| </ul>
| |
| See [[#Structure of XmlDoc for AddToRecord|Structure of XmlDoc for AddToRecord]] for a description of the XmlDoc created by LoadFromRecord.
| |
| </td></tr>
| |
| <tr><th>AttributeValues
| |
| </th><td>This name required argument is a Boolean value that indicates whether a field value will be stored as “XML text” or as an XML attribute (belonging to its field, which is an XmlDoc element).
| |
|
| |
| For example, <tt><APSUBUND>COMM</APSUBUND></tt> is text format, and <tt><APSUBUND value="COMM"/></tt> is attribute value format.
| |
|
| |
| The default value is <tt>False</tt>, which produces text format. In this format, the value of a field will be converted to base64 in the XmlDoc if the field contains a byte that is:
| |
| <ul>
| |
| <li>Equal to X'00', if the AllowNull property of the XmlDoc is <tt>False</tt>.
| |
| <li>Between X'00' and X'3F'.
| |
| <li>Not translatable from EBCDIC to Unicode, using either the standard Unicode translation table or the base codepage translation table, as determined by the <tt>CodepageTable=</tt> argument.
| |
| <li>Not invertible when translating from EBCDIC to Unicode and back to EBCDIC using the standard Unicode translation table, if the <var>CodepageTable</var> argument is <var>False</var>.
| |
| </ul>
| |
|
| |
| This argument must be <var>False</var> if the XmlDoc is to be used as the method object of the [[#AddToRecord subroutine in XmlDoc class|AddToRecord subroutine]].
| |
| </td></tr>
| |
| <tr><th>AttributeNames
| |
| </th><td>This name required argument is a Boolean value that indicates whether each field name is to be stored in the XmlDoc as an element name or as the value of a 'name' attribute.
| |
|
| |
| For example, <tt><APSUBUND>COMM</APSUBUND></tt> is element-name format, and the following is name-as-attribute format:
| |
| <p class="code"><nowiki><field name="APSUBUND">
| |
| COMM
| |
| </field>
| |
| </nowiki></p>
| |
|
| |
| The default value as of ''Sirius Mods'' version 7.6 (and maintenance back to version 7.3) is <tt>True</tt>, which produces name-as-attribute format. Formerly, the default value was <tt>False</tt>.
| |
|
| |
| The name-as-attribute format from the <tt>True</tt> option is better suited to operations on the XmlDoc, particularly a record copying operation. The element-name format from the <tt>False</tt> option produces more compact output when the XmlDoc is serialized.
| |
|
| |
| This argument must be <tt>True</tt> if the XmlDoc is to be used as the method object of the [[#AddToRecord subroutine in XmlDoc class|AddToRecord subroutine]].
| |
| </td></tr>
| |
| <tr><th>NamesToLower
| |
| </th><td>This name required argument is a Boolean value that indicates whether field names are stored in all lowercase characters. The default value is <tt>False</tt>, which does not translate uppercase name characters to lowercase.
| |
|
| |
| If the XmlDoc is to be used for record copying, this argument should probably be <tt>False</tt>.
| |
| </td></tr>
| |
| <tr><th>AllowUnreversible
| |
| </th><td>This name required argument is a Boolean value that indicates whether a request is cancelled if a field name would be changed irreversibly by lowercasing or by replacing with a period the characters that would be invalid in an XML document.
| |
|
| |
| The default value is <tt>False</tt>, which allows request cancellation to alert you about unreversible field names.
| |
|
| |
| If the XmlDoc is to be used for record copying, this argument should probably be <tt>False</tt>.
| |
| </td></tr>
| |
| <tr><th>CodepageTable
| |
| </th><td>This name required argument is a Boolean value; if <tt>True</tt>, the translations defined by the '''base''' Unicode codepage are used when translating from EBCDIC to Unicode for storing in the XmlDoc.
| |
|
| |
| This argument is for the unusual case where you anticipate that the XML document is to be used later by the [[#AddToRecord subroutine in XmlDoc class|AddToRecord subroutine]], and the standard Unicode translation tables in place when AddToRecord is invoked may differ from those in place when the record was copied to the XmlDoc.
| |
|
| |
| The default value is <tt>False</tt>, which uses the standard Unicode translation tables, including any modifications specified in UNICODE Trans or UNICODE Map commands. The advantage of using <tt>CodepageTable=False</tt> is that it will allow you to readily modify the XmlDoc directly (that is, with the AddElement and AddAttribute methods). Those operations will use the standard Unicode translation tables; there is no way to perform them using the base codepage translation tables.
| |
| </td></tr></table>
| |
|
| |
| All fields are copied to the XmlDoc by LoadFromRecord.
| |
|
| |
| See the [[#AddToRecord subroutine in XmlDoc class|AddToRecord subroutine]] for an example of extracting a record to an XmlDoc
| |
| for record copying, and see the [[ToXmlDoc (Record function)|ToXmlDoc function]] in the [[Record class]] for other
| |
| examples using the method arguments.
| |
|
| |
| This method was actually introduced in version 7.6 of
| |
| the ''Sirius Mods'', but the XmlNode class LoadFromRecord implementation prior to
| |
| version 7.8 required that the XmlDoc be empty.
| |
| | |
| ==AddToRecord subroutine in XmlDoc class==
| |
| This subroutine adds to the current record the fields and/or fieldgroups
| |
| that are contained in the method XmlDoc object according to the structure
| |
| created by the [[#LoadFromRecord subroutine in XmlDoc and XmlNode classes|LoadFromRecord subroutine]].
| |
| AddToRecord must be contained within a “record loop” (for example, an FRN
| |
| block), and must not be contained in a fieldgroup context.
| |
|
| |
|
| |
| The arguments to AddToRecord are:
| |
| <pre>
| |
| %doc:AddToRecord( -
| |
| [DisableFieldConstraints=bool] -
| |
| [, CopyIDs=bool] -
| |
| [, IgnoreUndefinedFields=bool] )
| |
| </pre>
| |
|
| |
| Where
| |
|
| |
| <dl>
| |
| <dt><i><b>%doc</b></i>
| |
| <dd>The method object is an XmlDoc whose structure conforms to that
| |
| created by the LoadFromRecord subroutine; see [[#Structure of XmlDoc for AddToRecord|Structure of XmlDoc for AddToRecord]].
| |
| <dt><b>DisableFieldConstraints= </b><i>bool</i>
| |
| <dd>This name required argument is a Boolean value; if <tt>True</tt>,
| |
| then various field constraints (such as LENGTH-EQ, which was introduced
| |
| in ''Model 204'' V7R2) are not checked when the fields are added to
| |
| the record.
| |
|
| |
| The default is <tt>False</tt>.
| |
| <dt><b>CopyIDs= </b><i>bool</i>
| |
| <dd>This name required argument is a Boolean value; if <tt>True</tt>,
| |
| then the fieldgroup IDs are copied, if possible,
| |
| from the XmlDoc (stored
| |
| as the 'groupID' attribute of 'fieldgroup' elements)
| |
| to the record, and
| |
| the 'maxGroupID' attribute value of the 'Record' element is also
| |
| used as the maximum fieldgroup ID in the record, if possible.
| |
| On any given 'fieldgroup' element, a 'groupID' attribute may be 0
| |
| or missing or not greater than the current maximum fieldgroup ID;
| |
| in any of these cases, a new fieldgroup ID is generated for the
| |
| fieldgroup occurrence.
| |
|
| |
| If <tt>False</tt>, new fieldgroup IDs are generated.
| |
|
| |
| The default is <tt>False</tt>.
| |
| <dt><b>IgnoreUndefinedFields= </b><i>bool</i>
| |
| <dd>This name required argument is a Boolean value; if <tt>True</tt>,
| |
| then:
| |
| <ul>
| |
| <li>If a field in the XmlDoc is not defined in the current file,
| |
| the field is ignored.
| |
| <li>If a fieldgroup in the XmlDoc is not defined in the current file,
| |
| the fieldgroup, and all descendants of the fieldgroup element,
| |
| are ignored.
| |
| </ul>
| |
|
| |
| If <tt>False</tt>, any field or fieldgroup in the XmlDoc that is not
| |
| defined in the current file throws an AddToRecordError exception.
| |
|
| |
| The default is <tt>False</tt>.
| |
| </dl>
| |
|
| |
| The AddToRecord subroutine can throw an [[#AddToRecordError exception class|AddToRecordError exception]].
| |
|
| |
| Fields in the XmlDoc that are defined as CAT or CTO are ignored by AddToRecord.
| |
|
| |
| Any fieldgroup update tracking fields in a fieldgroup
| |
| are automatically set when that fieldgroup is
| |
| created by AddToRecord, but no other updated tracking fields are automatically
| |
| set by the updates performed by AddToRecord.
| |
|
| |
| Any fields in the XmlDoc that are defined as update tracking fields are
| |
| copied to the record.
| |
| See [[#Removing update tracking fields from an XmlDoc|Removing update tracking fields from an XmlDoc]] for an example of removing update tracking fields
| |
| from AddToRecord's XmlDoc; generally this will not be needed, but it may be useful
| |
| in certain situations.
| |
|
| |
| The basic approach to copying a record from one file to another is:
| |
| <pre>
| |
| In SRCFILE FRN %source
| |
| %doc = %doc:NewFromRecord
| |
| End For
| |
| In TARGFILE Store Record
| |
| End Store
| |
| %targ = $CurRec
| |
| In TARGFILE FRN %targ
| |
| %doc:AddToRecord
| |
| End For
| |
| </pre>
| |
|
| |
| Some additional examples of record copying are shown in [[#Copying from multiple source records|Copying from multiple source records]].
| |
|
| |
| Note that this method was actually introduced in version 7.6 of
| |
| the ''Sirius Mods'', although until version 7.8 of the ''Sirius Mods'' an
| |
| exception was thrown if the version of ''Model 204'' in use was older than V7R2.
| |
| ===Copying from multiple source records===
| |
| Since the [[#LoadFromRecord subroutine in XmlDoc and XmlNode classes|LoadFromRecord subroutine]] can
| |
| extract from a record into a subtree of an Element node in an XmlDoc,
| |
| you can use it, together with AddToRecord, to combine multiple
| |
| source records into one target record.
| |
|
| |
| As a simple example, you can put the fields from two records
| |
| “side by side” into a target record:
| |
| <pre>
| |
| FRN %x
| |
| %doc = %doc:NewFromRecord
| |
| End For
| |
| %top = %doc:SelectSingleNode('*')
| |
| FRN %y
| |
| %top:LoadFromRecord
| |
| End For
| |
| Store Record
| |
| End Store
| |
| %rn = $CurRec
| |
| FRN %rn
| |
| %doc:AddToRecord
| |
| End For
| |
| </pre>
| |
|
| |
| The XmlDoc that is input to AddToRecord would have a structure
| |
| similar to the following:
| |
| <pre>
| |
| <Record ...>
| |
| <field ...>
| |
| ... first field from record %x
| |
| </field>
| |
| ...
| |
| <field ...>
| |
| ... first field from record %y
| |
| </field>
| |
| ...
| |
| </Record>
| |
| </pre>
| |
| Of course, you could also accomplish this particular objective by
| |
| using two XmlDocs:
| |
| <pre>
| |
| FRN %x
| |
| %doc1 = %doc1:NewFromRecord
| |
| End For
| |
| FRN %y
| |
| %doc2 = %doc2:NewFromRecord
| |
| End For
| |
| Store Record
| |
| End Store
| |
| %targ = $CurRec
| |
| FRN %targ
| |
| %doc1:AddToRecord
| |
| %doc2:AddToRecord
| |
| End For
| |
| </pre>
| |
|
| |
| You can also use LoadFromRecord to modify the fieldgroup structure
| |
| within a record (using V7R2 of ''Model 204'').
| |
| For example, you could take the “outer” fields of one
| |
| record and move them to be fieldgroup members in the target
| |
| record:
| |
| <pre>
| |
| In SRCFILE FRN %x
| |
| %doc = %doc:NewFromRecord
| |
| End For
| |
| %fg = %doc:SelectSingleNode('*/fieldgroup[@name="GRP"]')
| |
| In SRCFILE FRN %y
| |
| %fg:LoadFromRecord
| |
| End For
| |
| In TARGFILE Store Record
| |
| End Store
| |
| %rn = $CurRec
| |
| In TARGFILE FRN %rn
| |
| %doc:AddToRecord
| |
| PAI
| |
| End For
| |
| </pre>
| |
|
| |
| The use of a separate source and target file above (which in
| |
| general is a typical usage of the record copying methods) is
| |
| more or less required here, because the fields in SRCFILE are
| |
| defined as outer fields, but in TARGFILE they are defined as members of fieldgroup
| |
| GRP (or they would need to be “FIELDGROUP *” fields).
| |
| So, for example, definitions for SRCFILE might include:
| |
| <pre>
| |
| DEFINE FIELD FOO
| |
| DEFINE FIELDGROUP GRP
| |
| </pre>
| |
| and definitions for TARGFILE might include:
| |
| <pre>
| |
| DEFINE FIELDGROUP GRP
| |
| DEFINE FIELD FOO WITH FIELDGROUP GRP
| |
| </pre>
| |
| And the XmlDoc that is input to the above AddToRecord subroutine
| |
| may look like:
| |
| <pre>
| |
| <Record ...>
| |
| <fieldgroup name="GRP" ...>
| |
| <field name="FOO">
| |
| value of foo
| |
| </field>
| |
| </fieldgroup>
| |
| </Record>
| |
| </pre>
| |
| And the corresponding output of the above PAI would be:
| |
| <pre>
| |
| \GRP = 1
| |
| FOO = value of foo
| |
| /GRP = 1
| |
| </pre>
| |
| ===Removing update tracking fields from an XmlDoc===
| |
| In the simple situation, the record copying operation provided by LoadFromRecord
| |
| and AddToRecord produces a copy of all of the record's fields, including
| |
| update tracking fields (such as UPDATE-TIME fields).
| |
| However, in some circumstances, you may not want some of the update tracking fields
| |
| to be propagated by AddToRecord.
| |
| This can readily be accomplished by using DeleteSubtree to remove the tracking
| |
| fields you want to suppress (of course, DeleteSubtree could be used to remove
| |
| other fields and/or fieldgroups, as well).
| |
|
| |
| Consider an example in which AddToRecord is being used to add fields to a
| |
| record that already has fields stored in it:
| |
| <pre>
| |
| IN ?&SOURCE DEFINE FIELD REC.UPD WITH UPDATE-TIME
| |
| IN ?&SOURCE DEFINE FIELD FOO
| |
| IN ?&TARGET DEFINE FIELD REC.UPD WITH UPDATE-TIME
| |
| IN ?&TARGET DEFINE FIELD FOO
| |
| ...
| |
| Do the following on Monday:
| |
| In ?&SOURCE Store Record
| |
| FOO = 'Record stored on Monday'
| |
| End Store
| |
| %rn = $CurRec
| |
| In ?&SOURCE FRN %rn
| |
| %doc = %doc:NewFromRecord
| |
| End For
| |
| %serial = %doc:Serial
| |
| In LOG Store Record
| |
| RECORD.XML = %serial
| |
| End Store
| |
| ...
| |
| Do the following on Tuesday:
| |
| In LOG For 1 Record
| |
| %doc:LoadXml(RECORD.XML)
| |
| End For
| |
| In ?&TARGET Store Record
| |
| FOO = 'Record stored on Tuesday'
| |
| End Store
| |
| %rn = $CurRec
| |
| In ?&TARGET FRN %rn
| |
| %doc:AddToRecord
| |
| End For
| |
| </pre>
| |
| In this scenario, GRP.UPD would be set to Monday, overlaying the
| |
| more recent (and probably desired) value which was set on Tuesday.
| |
| To prevent this overlay, you can insert the following statement
| |
| after <tt>%doc:LoadXml(RECORD.XML)</tt>:
| |
| <pre>
| |
| %doc:DeleteSubtree('*/fieldgroup/field[@name="GRP.UPD"]')
| |
| </pre>
| |
| ===Structure of XmlDoc for AddToRecord===
| |
| The method object of the AddToRecord subroutine
| |
| is an XmlDoc whose structure conforms to that
| |
| created by the LoadFromRecord subroutine.
| |
| You can also create an XmlDoc to be used for AddToRecord; the rules for
| |
| the XmlDoc are described here.
| |
| The outline of the XmlDoc is:
| |
| <pre>
| |
| <Record [version="1"] [codepage="--codepage name--"]
| |
| [maxGroupID="--fieldgrouop counter--"]
| |
| [file="---file name---"] [number="---record number---"]>
| |
| <field name="---field name---">
| |
| ---field value---
| |
| </field>
| |
| <field name="---field name---" encoding="base64">
| |
| ---base64 encoded field value---
| |
| </field>
| |
| <fieldgroup name="---fieldgroup name---"
| |
| [groupID="---fieldgroup ID---"]>
| |
| <field ...
| |
| <fieldgroup ...
| |
| ...
| |
| </fieldgroup>
| |
| ...
| |
| </Record>
| |
| </pre>
| |
|
| |
| The requirements for the XmlDoc are:
| |
| <dl>
| |
| <dt>Comments and PIs
| |
| <dd>Comment and PI nodes are allowed anywhere in the XmlDoc.
| |
| <dt>Elements in non-null namespaces
| |
| <dd>In addition to the elements mentioned below for the various
| |
| elements contained in the XmlDoc, the 'Record' and 'fieldgroup'
| |
| elements may have any additional
| |
| child elements which are in any non-null namespace.
| |
| These additional elements are ignored.
| |
| For example, the following is a valid AddToRecord XmlDoc
| |
| representing an empty record:
| |
| <pre>
| |
| <Record>
| |
| <foo:bar xmlns:foo="u:xyz"/>
| |
| </Record>
| |
| </pre>
| |
| However, the only null-namespace child elements permitted of
| |
| elements in the null
| |
| namespace are those described for each element type below.
| |
| For example, the following is an invalid AddToRecord XmlDoc:
| |
| <pre>
| |
| <Record>
| |
| <foo/>
| |
| </Record>
| |
| </pre>
| |
| <dt>Attributes in non-null namespaces
| |
| <dd>In addition to the attributes mentioned below for the various
| |
| elements contained in the XmlDoc, those elements may contain
| |
| any additional attributes which are in any non-null namespace.
| |
| These additional attributes are ignored.
| |
| For example, the following is a valid AddToRecord XmlDoc
| |
| representing an empty record:
| |
| <pre>
| |
| <Record foo:bar="x" xmlns:foo="u:xyz"/>
| |
| </pre>
| |
| Of course, elements in non-null namespaces may have any attributes.
| |
| The only attributes permitted in elements in the null
| |
| namespace are those described below.
| |
| For example, the following is an invalid AddToRecord XmlDoc:
| |
| <pre>
| |
| <Record foo="x"/>
| |
| </pre>
| |
| <dt>Record element
| |
| <dd>The top level element of the XmlDoc must be named 'Record';
| |
| all of its attributes are optional and are described below.
| |
| The element children of the 'Record' element are optional; they may be:
| |
| <ul>
| |
| <li>field
| |
| <li>fieldgroup
| |
| </ul>
| |
|
| |
| The 'Record' element may not have a Text child node.
| |
| <dt>version attribute of Record element
| |
| <dd>If present, this attribute must have the numeric value '1'.
| |
| <dt>codepage
| |
| <dd>If present, this attribute contains the name of the codepage
| |
| whose base translation tables are used for converting the Unicode
| |
| field names and field values (if not base 64 encoded) in the XmlDoc
| |
| to EBCDIC.
| |
| <dt>maxGroupID attribute of Record element
| |
| <dd>If present, this attribute contains the value of the maximum
| |
| fieldgroup ID to be set (if greater than or equal to all of the
| |
| fieldgroup IDs stored in the record)
| |
| in the added record, if the <tt>CopyIDs=True</tt>
| |
| argument is provided.
| |
| This must be a non-negative integer value.
| |
| <dt>file attribute of Record element
| |
| <dd>This attribute is ignored.
| |
| <dt>number attribute of Record element
| |
| <dd>If present, this must either be "-1", signifying that the input record
| |
| number is not known, or must be a non-negative integer value.
| |
| As noted in [[Compatibility/Bug fixes in V7.8#AddToRecord constraint on 'number' attribute|AddToRecord constraint on 'number' attribute]], this represents a compatibility issue.
| |
| <dt>field element
| |
| <dd>The 'field' element may be a child of either the 'Record' or
| |
| 'fieldgroup' element; it contains a field occurrence.
| |
| It must have a 'name' attribute, and may have an 'encoding' attribute.
| |
| It may have one Text child, which is either the value of the occurrence or, if
| |
| the 'encoding' attribute is present (with the value 'base64'), is the
| |
| base 64 encoded value of the occurrence.
| |
| <dt>name attribute of field element
| |
| <dd>This attribute is required; it is the name of the field.
| |
| <dt>encoding attribute of field element
| |
| <dd>This attribute is optional; if present, it must have the value 'base64',
| |
| indicating that the Text child of the 'field' element is the base 64
| |
| encoding of the field value.
| |
| <dt>fieldgroup element
| |
| <dd>The 'fieldgroup' element may be a child of either the 'Record' or
| |
| 'fieldgroup' element; it is the top of a subtree representing a fieldgroup
| |
| occurrence.
| |
| The element children of the 'fieldgroup' element are optional; they may be:
| |
| <ul>
| |
| <li>field
| |
| <li>fieldgroup
| |
| </ul>
| |
|
| |
| The fieldgroup element may not have a Text child node.
| |
| It must have a 'name' attribute, and may have a 'groupID' attribute.
| |
| <dt>name attribute of fieldgroup element
| |
| <dd>This attribute is required; it is the name of the fieldgroup.
| |
| <dt>groupID attribute of fieldgroup element
| |
| <dd>If present, this attribute contains the value of the
| |
| fieldgroup ID to be set (if possible) for the fieldgroup occurrence
| |
| in the added record, if the <tt>CopyIDs=True</tt>
| |
| argument is provided.
| |
| </dl>
| |
| ===AddToRecordError exception class===
| |
| The members of the AddToRecordError exception class are described below.
| |
| Except for the constructor, <tt>New</tt>, all class members are
| |
| read-only properties:
| |
| <dl>
| |
| <dt>Reason
| |
| <dd>An enumeration of type AddToRecordErrorReason.
| |
| The possible values are:
| |
| <dl>
| |
| <dt>InvalidNode
| |
| <dd>A node in the XmlDoc does not conform to the structure as
| |
| created by the LoadFromRecord subroutine.
| |
| <dt>UntranslatableFieldName
| |
| <dd>A field name in the XmlDoc is not translatable to EBCDIC.
| |
| <dt>UntranslatableFieldgroupName
| |
| <dd>A fieldgroup name in the XmlDoc is not translatable to EBCDIC.
| |
| <dt>UntranslatableValue
| |
| <dd>A field value in the XmlDoc is not translatable to EBCDIC.
| |
| <dt>InvalidBase64
| |
| <dd>A string used for the base64 encoding of a field in the
| |
| XmlDoc is not a valid base64 string.
| |
| <dt>FieldNameTooLong
| |
| <dd>A field name in the XmlDoc is longer than 255 characters.
| |
| <dt>FieldgroupNameTooLong
| |
| <dd>A fieldgroup name in the XmlDoc is longer than 255 characters.
| |
| <dt>ValueTooLong
| |
| <dd>The value of a field in the XmlDoc that is not defined as a
| |
| LOB field in the current file is longer than 255 characters or is
| |
| longer than the defined LEN attribute, if the field is a fixed
| |
| OCCURS field.
| |
| <dt>UnknownFieldName
| |
| <dd>A field name in the XmlDoc is not defined in the current file.
| |
| <dt>UnknownFieldgroupName
| |
| <dd>A fieldgroup name in the XmlDoc is not defined in the current file.
| |
| <dt>ExpectedField
| |
| <dd>A field name in the XmlDoc is defined as a fieldgroup
| |
| in the current file.
| |
| <dt>ExpectedFieldgroup
| |
| <dd>A fieldgroup name in the XmlDoc is defined as a field
| |
| in the current file.
| |
| <dt>ErrorAddingField
| |
| <dd>An error occurred adding a field, such as a violation of a
| |
| field constraint.
| |
| <dt>ErrorAddingFieldgroup
| |
| <dd>An error occurred adding a fieldgroup, such as a file full
| |
| condition.
| |
| <dt>ErrorObtainingRecord
| |
| <dd>AddToRecord was unable to lock the record in exclusive mode.
| |
| <dt>InvalidFieldgroupID
| |
| <dd>A fieldgroup ID in the XmlDoc is not numeric.
| |
| <dt>InvalidCodepage
| |
| <dd>The codepage name specified on the 'codepage' attribute of the
| |
| 'Record' element is not a known codepage name.
| |
| <dt>ErrorAddingMaxFieldgroupID
| |
| <dd>The attempt to set the fieldgroup ID counter in the record
| |
| failed; this is a very unusual condition.
| |
| <dt>InsufficientStorageForLOB
| |
| <dd>STBL, VTBL, or User Buffer storage was unavailable.
| |
| The <tt>Description</tt> property indicates which of these is applicable.
| |
| <dt>InvalidVersion
| |
| <dd>Invalid value of the 'version' attribute of the 'Record' element;
| |
| the only allowed value is 1.
| |
| <dt>InvalidInputRecordNumber
| |
| <dd>Invalid value of the 'number' attribute of the 'Record' element;
| |
| it must either be "-1" or a non-negative integer.
| |
| </dl>
| |
| <dt>Description
| |
| <dd>A message that explains the error.
| |
| <dt>UntranslatableHexValue
| |
| <dd>If the Reason indicates that a string in the XmlDoc is not translatable
| |
| to EBCDIC, this contains the hexadecimal representation of the Unicode
| |
| codepoint which is not translatable.
| |
| <dt>FieldOrFieldgroupName
| |
| <dd>If the error involves a field or fieldgroup (for example,
| |
| if <tt>Reason = ErrorAddingField</tt>), this is the field or fieldgroup name.
| |
| <dt>NodeName
| |
| <dd>If the error involves a named node in the XmlDoc (for example, some cases
| |
| when <tt>Reason = InvalidNode</tt>), this is the name of the node.
| |
| <dt>NodeType
| |
| <dd>If the error involves a node in the XmlDoc (for example, all cases
| |
| when <tt>Reason = InvalidNode</tt>), this an XmlNodeType enumeration value of the
| |
| type of the node.
| |
| <dt>Value
| |
| <dd>If the error involves a value in the XmlDoc (for example,
| |
| when <tt>Reason = InvalidBase64</tt>), this is the value that is in error
| |
| (actually, up to 255 bytes of the value).
| |
| <dt>InputRecordNumber
| |
| <dd>The value of the 'number' attribute of the 'Record' element in the XmlDoc.
| |
| <dt>New
| |
| <dd>The constructor for the class, <tt>New</tt> lets you set values for each
| |
| member of the class.
| |
| <pre>
| |
| %ex = New ( Reason = reasonEnum -
| |
| [, Description = string] -
| |
| [, UntranslatableHexValue = hexString] -
| |
| [, FieldOrFieldgroupName = string] -
| |
| [, NodeName = string] -
| |
| [, NodeType = xmlNodeTypeEnum] -
| |
| [, Value = string] -
| |
| [, InputRecordNumber = number])
| |
| </pre>
| |
|
| |
| The Reason argument is required;
| |
| all other arguments are optional, name required.
| |
| The default value of InputRecordNumber is -1; all other
| |
| default values are the
| |
| null string or the Null object, as appropriate.
| |
| </dl>
| |
|
| |
| Note that this class was actually introduced in version 7.6 of the ''Sirius Mods''.
| |
| ==MoveNamespace argument for AddTopElement==
| |
| The following optional, name required argument has been added to the
| |
| AddTopElement function in the XmlDoc class:
| |
| <pre>
| |
| MoveNamespace=boolean
| |
| </pre>
| |
| If MoveNamespace=True and a URI argument (with a non-null string) is
| |
| provided, then
| |
| if the "old" top element contains a namespace
| |
| declaration which is the same as the declaration inserted due to the
| |
| URI argument, the declaration is deleted from the old top element.
| |
|
| |
| Note: You should use MoveNamespace=True only when some consumer of
| |
| the XML document cares about not having the redundant declaration.
| |
| This would be an unusual situation, because the information
| |
| content of the document does not change.
| |
| Using MoveNamespace=True
| |
| might trigger a scan of the entire XmlDoc, which AddTopElement does not
| |
| normally do.
| |
|
| |
| ==DeleteTopElement subroutine in XmlDoc class==
| |
| The syntax for DeleteTopElement is:
| |
| <pre>
| |
| doc:DeleteTopElement
| |
| </pre>
| |
| This subroutine removes the top Element from an XmlDoc, and
| |
| make its children be the “middle siblings” of the left and right siblings
| |
| of the deleted Element.
| |
| <ul>
| |
| <li>The deleted element may not have more than one
| |
| Element child.
| |
| <li>The deleted element may not have a Text child.
| |
| </ul>
| |
|
| |
| In common usage, the Element child of the deleted Element will become the
| |
| new top Element of the XmlDoc.
| |
| 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:
| |
| <pre>
| |
| <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
| |
| <soap:Body>
| |
| <data>
| |
| ...
| |
| </data>
| |
| </soap:Body>
| |
| </soap:Envelope>
| |
| </pre>
| |
| Then the following User Language fragment:
| |
| <pre>
| |
| %xdoc:DeleteTopElement
| |
| %xdoc:DeleteTopElement
| |
| </pre>
| |
| Results in the following contents of %xdoc:
| |
| <pre>
| |
| <data>
| |
| ...
| |
| </data>
| |
| </pre>
| |
|
| |
| The remaining considerations for using DeleteTopElement
| |
| concern the occurrence of namespace declarations in the
| |
| XmlDoc; there are a few details to explain how they are
| |
| manipulated, and to explain how the performance of
| |
| DeleteTopElement is affected.
| |
|
| |
| As shown in the “SOAP wrapper removal” example above,
| |
| DeleteTopElement will remove from the XmlDoc any namespace
| |
| declarations (in this example, <tt>xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"</tt>)
| |
| which '''are not''' referenced after removing the top Element.
| |
| Note that a variant on the above example can occur using a
| |
| default namespace declaration:
| |
| <pre>
| |
| <Envelope xmlns"http://schemas.xmlsoap.org/soap/envelope/">
| |
| <Body>
| |
| <data xmlns="">
| |
| ...
| |
| </data>
| |
| </Body>
| |
| </Envelope>
| |
| </pre>
| |
| Then the following User Language fragment:
| |
| <pre>
| |
| %xdoc:DeleteTopElement
| |
| %xdoc:DeleteTopElement
| |
| </pre>
| |
| Results in the following contents of %xdoc:
| |
| <pre>
| |
| <data xmlns="">
| |
| ...
| |
| </data>
| |
| </pre>
| |
|
| |
| As seen in this example, the null namespace declaration is not
| |
| removed, even though it is not, strictly speaking, needed.
| |
|
| |
| In addition, DeleteTopElement will move, to the new top Element,
| |
| any namespace declarations which '''do''' continue to be
| |
| referenced after the top Element deletion:
| |
| <pre>
| |
| %n = %d:AddElement('foo', , 'u:uri')
| |
| %n:AddElement('bar', , 'u:uri')
| |
| %d:Print
| |
| %d:DeleteTopElement
| |
| Print 'After deletion:'
| |
| %d:Print
| |
| </pre>
| |
| The result of the above User Language fragment is:
| |
| <pre>
| |
| <foo xmlns="u:uri">
| |
| <bar/>
| |
| </foo>
| |
| After deletion:
| |
| <bar xmlns="u:uri"/>
| |
| </pre>
| |
| Regarding the performance of
| |
| DeleteTopElement, it 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,
| |
| there are three reasons that the descendants
| |
| of the new top Element need to be recursively visited:
| |
| <ol>
| |
| <li>Fixing references to 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
| |
| up.
| |
| A count is kept to the total references to moved namespace
| |
| declarations; when this goes to zero there is no more need to do this.
| |
| So, for example:
| |
| <pre>
| |
| <p:oldTop xmlns:p="p:uri">
| |
| <p:newTop>
| |
| <child/>
| |
| </p:newTop>
| |
| </p:oldTop>
| |
| </pre>
| |
| The p:newTop element needs to have it's namespace reference
| |
| fixed, but that is the only reference to it, so there is no
| |
| need to visit child.
| |
| <li>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 up to point to the first non-deleted
| |
| declaration following the deleted one.
| |
| This is not needed by the descendants of any element which has a
| |
| namespace declaration (in the original XmlDoc).
| |
| So, for example:
| |
| <pre>
| |
| <p:oldTop xmlns:p="p:uri">
| |
| <newTop>
| |
| <q:child xmlns:q="q:uri">
| |
| <grandchild/>
| |
| </q:child>
| |
| </newTop>
| |
| </p:oldTop>
| |
| </pre>
| |
| Both newTop and q:child need to have their namespace pointers
| |
| fixed up, but since q:child has a namespace declaration,
| |
| grandchild doesn't need to be fixed up, so it doesn't need to
| |
| be visited.
| |
| <li>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, indicating that a non-null default
| |
| namespace declaration may 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 one using a default namespace).
| |
| The need to set this state is eliminated in descendants of an element
| |
| which has a default namespace declaration (either null or not).
| |
| So, for example:
| |
| <pre>
| |
| <oldTop xmlns="p:uri">
| |
| <newTop>
| |
| <q:child xmlns="q:uri">
| |
| <grandchild/>
| |
| </q:child>
| |
| </newTop>
| |
| </p:oldTop>
| |
| </pre>
| |
| The state needs to be fixed at newTop, but since q:child has
| |
| a default namespace declaration, the state at grandchild
| |
| doesn't need to be fixed up, so it doesn't need to be
| |
| visited.
| |
| </ol>
| |
|
| |
| {{Hierarchy footer}}
| |