Creating Templates for the Get Methods

Basic Structure of a Get Template

In a GetMetadata or GetMetadataObjects method call, a template is a metadata property string that specifies attributes and associations to retrieve for a specified metadata type.
  • A template that requests simple attributes looks like this:
    <MetadataType Attribute1="" Attribute2="" Attribute3=""/>
    MetadataType can be the same metadata type as what is specified in the INMETADATA parameter, an associated metadata type that is requested by an association name in the INMETADATA parameter, or, if the OMI_INCLUDE_SUBTYPES (16) flag is set, a supertype of the metadata type in the INMETADATA parameter. Attributen are attributes that are defined for the specified metadata type in the SAS Metadata Model.
  • A template that requests associated objects looks like this:
    <MetadataType>
      <AssociationName/>
    </MetadataType>
    
    AssociationName is an association name that is valid for MetadataType as defined in the SAS Metadata Model. This request returns associated object instances of all metadata types that are valid for the specified AssociationName. You can specify AssociationName as many times as you need to, as long as each association name is valid for MetadataType.
  • A template can specify to retrieve both attributes and associations in the same request, as long as all of the attributes and associations are valid for MetadataType. For example:
    <MetadataType Id="" Name="" Attributen="">
      <AssociationName1/>
      <AssociationName2/>
    </MetadataType>
  • When templates are used, the GetMetadata method returns only the Id attribute of associated objects. To get additional attributes for associated objects, set the OMI_ALL_SIMPLE (8) flag, which gets all simple attributes for all requested objects and associated objects. Or, specify additional templates that request specific attributes, as follows:
    <MetadataType>
       <AssociationName/>
     </MetadataType>
     <AssociatedMetadataType1 Id="" Name="" Attributen=""/>
     <AssociatedMetadataType2 Id="" Name="" Attributen=""/>
     
    AssociatedMetadataType1 and AssociatedMetadataType2 are metadata types that are valid for AssociationName in the SAS Metadata Model. Specifying an associated metadata type does not prevent GetMetadata from returning information about objects of other metadata types that are valid for AssociationName. It just specifies attributes to retrieve for objects of the specified associated metadata type. The request returns the Id values of any other valid metadata types that are found.
  • Here is an example of how an additional template is used to retrieve an association of an associated object:
     <MetadataType>
       <AssociationName1/>
     </MetadataType>
     <AssociatedMetadataType>
       <AssociationName2/>
     </AssociatedMetadataType>
    
    AssociationName2 is an association name that is valid for AssociatedMetadataType as defined in the SAS Metadata Model.
  • You can specify associated object requests as deeply within an association path as you would like. For example:
    <MetadataType>
       <AssociationName1/>
     </MetadataType>
     <AssociatedMetadataType>
       <AssociationName2/>
     </AssociatedMetadataType> 
    <AssociatedMetadataType2>
       <AssociationName3/>
     </AssociatedMetadataType2> 
    <AssociatedMetadataType3>
       <AssociationName4/>
     </AssociatedMetadataType3>
    <AssociatedMetadataType4 Attributen=""/>
    In this example, AssociatedMetadataType is a valid metadata type for AssociationName1 in the SAS Metadata Model. AssociatedMetadataType2 is a valid metadata type for AssociationName2 in the SAS Metadata Model. AssociatedMetadataType3 is a valid metadata type for AssociationName3 in the SAS Metadata Model, and so on.
  • In the preceding request, the SAS Metadata Server returns the specified information for each specified associated metadata type, and the Id values of object instances of other metadata types that are valid for each AssociationName. To filter the objects that are returned for an association, you can use the Search attribute in AssociationName. When Search is used, the SAS Metadata Server retrieves only objects that meet the criteria specified in the Search attribute. The Search attribute supports filtering by metadata type, attribute, and association path criteria, alone or combined. For example:
    • To get only associated objects of a specified metadata type, specify Search as follows:
      <MetadataType>
         <AssociationName Search="AssociatedMetadataType"/>
      </MetadataType>
    • To get associated objects of a specified metadata type that have Attribute="X", specify Search as follows:
      <MetadataType>
         <AssociationName Search="AssociatedMetadataType[@Attribute='X']"/>
      </MetadataType>
    • To get only associated objects of a specified metadata type that have a specified association, specify Search as follows:
      <MetadataType>
         <AssociationName Search="AssociatedMetadataType[AssociationName/
      AssociatedMetadataType2]"/>
      </MetadataType>

Examples of Basic Output

Here are some simple examples of how templates are applied with real metadata types. Here is an example of a template that requests attribute values for a PhysicalTable object:
<PhysicalTable IsDBMSView="" IsEncrypted="" SASTableName=""/>
This is sample output from the request:
<PhysicalTable Id="A5TJRDIT.B200000J" IsDBMSView="0" IsEncrypted="0"
SASTableName="EMPINFO"/>
Here is an example of a template that requests objects associated to the table through the Columns association:
<PhysicalTable>
   <Columns/>
</PhysicalTable>
This is sample output from the request, reformatted for readability:
<PhysicalTable Id="A5TJRDIT.B200000J">
   <Columns>
     <Column Id="A5TJRDIT.B700002A"/>
     <Column Id="A5TJRDIT.B700002B"/>
     <Column Id="A5TJRDIT.B700002C"/>
     <Column Id="A5TJRDIT.B700002D"/>
     <Column Id="A5TJRDIT.B700002E"/>
     <ColumnRange Id="A5TJRDIT.BK000002"/>
   </Columns>
</PhysicalTable>
The SAS Metadata Server returns the Id values of all associated objects of all metadata types that are valid for the Columns association name. The Columns association name supports associations to objects of the Column and ColumnRange metadata types.
The following example requests additional attributes for the Column and ColumnRange object:
<PhysicalTable>
   <Columns/>
</PhysicalTable>
 <Column Id="" Name="" MetadataCreated="" MetadataUpdated=""/>
This is sample output from the request, reformatted for readability:
<PhysicalTable Id="A5TJRDIT.B200000J">
 <Columns>
   <Column Id="A5TJRDIT.B700002A" Name="DEPTCODE" MetadataCreated="10Jan2011:21:20:36" 
MetadataUpdated="10Jan2011:21:20:36"/>
   <Column Id="A5TJRDIT.B700002B" Name="NAME" MetadataCreated="10Jan2011:21:20:36"
MetadataUpdated="10Jan2011:21:20:36"/>
   <Column Id="A5TJRDIT.B700002C" Name="ADDR1" MetadataCreated="10Jan2011:21:20:36" 
MetadataUpdated="10Jan2011:21:20:36"/>
   <Column Id="A5TJRDIT.B700002D" Name="ADDR2" MetadataCreated="10Jan2011:21:20:36"
MetadataUpdated="10Jan2011:21:20:36"/>
   <Column Id="A5TJRDIT.B700002E" Name="IDNUM" MetadataCreated="10Jan2011:21:20:36" 
MetadataUpdated="14Jan2011:22:37:17"/>
   <ColumnRange Id="A5TJRDIT.BK000002"/>
 </Columns>
</PhysicalTable>
The request continues to return the Id value of the one ColumnRange object.
Here is an example of a template that requests only associated ColumnRange objects, and a template that requests basic attributes for the ColumnRange object:
<PhysicalTable>
  <Columns search="ColumnRange"/>
</PhysicalTable>
<ColumnRange Id="" Name="" MetadataCreated="" MetadataUpdated=""/>
Here is sample output from the request, reformatted for readability:
<PhysicalTable Id="A5TJRDIT.B200000J">
 <Columns SEARCH="ColumnRange">
  <ColumnRange Id="A5TJRDIT.BK000002" Name="Test" MetadataCreated="15Mar2011:19:37:31"
MetadataUpdated="15Mar2011:19:37:31"/>
 </Columns>
</PhysicalTable>
Here is an example of a template that requests only associated Column objects that have Name="DEPTCODE", and a template that requests basic attributes for the Column object:
<PhysicalTable>
  <Columns search="Column[@Name='DEPTCODE']"/>
</PhysicalTable>
<Column Id="" Name="" MetadataCreated="" MetadataUpdated=""/>
Here is sample output from the request, reformatted for readability:
<PhysicalTable Id="A5TJRDIT.B200000J">
 <Columns SEARCH="Column[@Name='DEPTCODE']">
  <Column Id="A5TJRDIT.B700002A" Name="DEPTCODE" MetadataCreated="10Jan2011:21:20:36"
MetadataUpdated="10Jan2011:21:20:36"/>
 </Columns>
</PhysicalTable>
Here is an example of a template that requests only Column objects that have indexes defined for them, and a template that requests basic attributes for the Column object:
<PhysicalTable>
  <Columns search="Column[Indexes/Index]"/>
</PhysicalTable>
<Column Id="" Name="" MetadataCreated="" MetadataUpdated=""/>
Here is sample output from the request, reformatted for readability:
<PhysicalTable Id="A5TJRDIT.B200000J">
  <Columns SEARCH="Column[Indexes/Index]">
   <Column Id="A5TJRDIT.B700002E" Name="IDNUM" MetadataCreated="10Jan2011:21:20:36"
MetadataUpdated="14Jan2011:22:37:17"/>
  </Columns>
</PhysicalTable>
The GetMetadata method supports the Search attribute in the association name subelements of the INMETADATA property string and the <TEMPLATES> element. When search criteria are specified in both the INMETADATA parameter and in the <TEMPLATES> element, the criteria in the INMETADATA parameter takes precedence. For more information, see Filtering the Associated Objects That Are Returned by a GetMetadata Request.
The GetMetadataObjects method supports the Search attribute in a template only. For more information, see Filtering the Associated Objects That Are Returned by a GetMetadataObjects Request.

New Get Template Form

In GetMetadata, the new form has the following basic format:
<GetMetadata>
 <Metadata>
  <MetadataType TemplateName="1"/> 
 </Metadata>
 <Ns>SAS</Ns>
 <Flags>4</Flags>
 <Options>
 <Templates>
 <Template TemplateName="1"> 1
 <MetadataType Name="" Attribute1="" Attribute2="" Attribute3="">
  <AssociationName1 Search="AssociatedMetadataType1"/> 2
   <AssociatedMetadataType1 Match="criteria1" TemplateExpand="Yes" TemplateName="2"/>
   <AssociatedMetadataType1 Match="criteria2" TemplateExpand="Yes" TemplateName="3"/>
   <AssociatedMetadataType1 TemplateExpand="No"/>  
  </AssociationName1>
  <AssociationName2/> 3
 </MetadataType>
 <AssociatedMetadataType2 Name="" Attribute1="">  4
   <AssociationName/>
 </AssociatedMetadataType2>
 </Template>
 <Template TemplateName="2"> 5
 <AssociatedMetadataType Name="" Attribute1="" Attribute2="" >
   <AssociationNameX/>
 </AssociatedMetadataType>
 </Template>
 <Template TemplateName="3">
 <AssociatedMetadataType Name="" Attribute1="" Attribute2="" >
   <AssociationNameY/>
 </AssociatedMetadataType>
 </Template>
</Templates>
</Options>
</GetMetadata>
1Template property strings are submitted in a <TEMPLATE> subelement of the <TEMPLATES> element in the OPTIONS parameter. The TemplateName attribute value in the first <TEMPLATE> subelement maps to the TemplateName value in the metadata property string in the INMETADATA parameter of the method call. The template property string specifies the primary metadata type and the attributes and associations that will be expanded in the request.
Note: The <TEMPLATE> subelement, which expands the primary object, is shown first to simplify the explanation. But, it does not need to be specified first. Named templates can be listed in any order in the <TEMPLATES> element.
2The first AssociationName subelement specifies the Search attribute to filter the request to return only objects of metadata type AssociatedMetadataType1. It is followed by subelements to indicate that different handling of objects of AssociatedMetadataType1 is needed, based on criteria specified in the Match attribute.
  • Object instances that meet Match= “criteria1” will be expanded by the template indicated in TemplateName=“2”.
  • Object instances that meet Match=“criteria2” will be expanded by the template indicated in TemplateName=“3”.
  • Object instances that meet neither criteria will have only their Id values returned.
When a TemplateName attribute is encountered in another template, the SAS Metadata Server deactivates the current template, and makes the new template active. When processing of the named template completes, it reactivates and continues with the initial template.
3The second AssociationName subelement behaves the same as it did in the legacy template. The SAS Metadata Server will return object instances of all metadata types that are valid for the specified association name. It returns only the Id values of any objects that are found unless you specify additional templates to indicate the attributes and associations that you would like returned for each object type. When reading additional templates, the server makes an exact metadata type match, unless the OMI_INCLUDE_SUBTYPES flag is set. For more information, see Templates and the OMI_INCLUDE_SUBTYPES Flag.
4This is an additional template. You can specify as many additional templates as you need. You can invoke the TemplateName attribute in an additional template as well.
5This is the second of the three named templates in the request. AssociatedMetadataType is the same metadata type as what is in the property string containing the corresponding TemplateName attribute value, or it is a supertype if the OMI_INCLUDE_SUBTYPES flag is set.
In GetMetadataObjects, the new form has the following basic format:
<GetMetadataObjects>
<Reposid>A0000001.XXXXXXXX</Reposid>
<Type>MetadataType</Type>
<Objects/>
<Ns>SAS</Ns>
<Flags>260</Flags>
<Options>
<Templates>
<Template TemplateName="MetadataType"> 1
<MetadataType>
 <AssociationName1 Search="AssociatedMetadataType1"> 2
  <AssociatedMetadataType1 Match="criteria1" TemplateExpand="Yes" TemplateName="1"/>
  <AssociatedMetadataType1 Match="criteria2" TemplateExpand="Yes" TemplateName="2"/>
  <AssociatedMetadataType1 TemplateExpand="No"/>
 </AssociationName1>
 <AssociationName2/>
</MetadataType>
<AssociatedMetadataType2 Name="" Attribute1=""> 3
  <AssociationName/>
</AssociatedMetadataType2>
</Template>
<Template TemplateName="1"> 
<AssociatedMetadataType Name="" Attribute="">
  <AssociationNameA/>
</AssociatedMetadataType>
</Template>
<Template TemplateName="2">
<AssociatedMetadataType Name="" Attribute="">
  <AssociationNameB/>
</AssociatedMetadataType>
</Template>
</Templates>
</Options>
</GetMetadataObjects>
1Because GetMetadataObjects does not accept an input metadata property string, you specify the metadata type from the TYPE parameter in the TemplateName attribute of the <TEMPLATE> subelement. The metadata property string in the <TEMPLATE> subelement specifies the metadata type, attributes, and association names to expand.
2The Search, Match, TemplateName, and TemplateExpand attributes behave as they do in GetMetadata.
3Additional templates behave as they do in GetMetadata.
Using the TemplateName attribute to redirect processing to a new template should be reserved for complex requests. Additional templates are adequate for expanding associated objects most of the time.

Examples of How the New Template Form Can Be Used

The following example uses the new template form in a GetMetadata request to query the contents of a folder. A folder is represented in a SAS Metadata Repository by the Tree metadata type. A Tree has a Members association to the objects that it contains. The initial template, named “MyTree”, uses the TemplateName attribute to specify different templates for expanding PhysicalTable objects, ClassifierMap objects, and Job objects. The Match attribute specifies different handling of the ClassifierMap objects that have a PublicType attribute value of “StoredProcess” versus those that do not. ClassifierMap objects that do not meet the Match attribute requirements, and other metadata objects found that are valid for the Members association name will be expanded with the attributes defined in the named template specified for the Root object. The request sets the OMI_INCLUDE_SUBTYPES (16) flag, in addition to the OMI_TEMPLATES (4) flag. The OMI_INCLUDE_SUBTYPES flag causes the server to return the properties specified for the Root metadata type for all subtypes.
Template “StoredProcess” specifies attributes to retrieve, and specifies to retrieve any objects associated through the ComputeLocations and Prompts association names. Template “Job” specifies attributes to retrieve for each Job object, and specifies to retrieve any objects associated through the JobActivities, TransformationSources, and TransformationTargets association names. An additional template requests attributes and associations to expand for any TransformationActivity objects that are found. Template “Table” specifies attributes to retrieve for each PhysicalTable object that is found, and requests any objects associated to PhysicalTable objects through the Columns, Indexes, and UniqueKeys association names. Additional templates request attributes for any returned Column, Index, and UniqueKey objects.
<GetMetadata>
 <Metadata>
 <Tree Id="A5MFRU33.AI0001JM" TemplateName="MyTree"/> 
 </Metadata>
 <Ns>SAS</Ns> 
 <Flags>20</Flags> 
 <Options>
  <Templates>
   <Template TemplateName="MyTree">
   <Tree Id="" Name="" Desc="" PublicType="">
   <Members>
   <PhysicalTable TemplateName="Table"/> 
   <ClassifierMap Match="@PublicType='StoredProcess'" 
   TemplateName="StoredProcess"/> 
   <Job TemplateName="Job"/> 
   <Root Templatename="dflt"/> 
   </Members>
   </Tree>
   </Template>
   <Template TemplateName="dflt">
   <Root Id="" Name=""/> 
   </Template>
   <Template TemplateName="StoredProcess">
   <ClassifierMap Id="" Name="" Desc="" PublicType="" 
   IsActive="" IsUserDefined="" TransformRole="">
   <ComputeLocations/> 
   <Prompts/> 
   </ClassifierMap>
   <Root Id="" Name=""/> 
   </Template>
   <Template TemplateName="Job">
   <Job Id="" Name="" Desc="" PublicType="" IsActive="" 
   IsUserDefined="" TransformRole="">
   <JobActivities/> 
   <TransformationSources/> 
   <TransformationTargets/> 
   </Job>
   <TransformationActivity Id="" Name="" Desc="">
   <Steps/> 
   </TransformationActivity>
   <Root Name="" Desc=""/> 
   </Template>
   <Template TemplateName="Table">
   <PhysicalTable Id="" Name="" Desc="" PublicType="" 
   IsCompressed="" DBMSType="">
   <Columns/> 
   <Indexes/> 
   <UniqueKeys/> 
   </PhysicalTable>
   <Column Id="" Name="" Desc="" SASColumnType="" SASColumnLength="" 
   SASFormat="" SASInformat=""/> 
   <Index Id="" Name="" Desc="" IndexName="" IsClustered="" 
   IsUnique=""/> 
   <UniqueKey Id="" Name="" Desc=""/> 
   </Template>
  </Templates>
 </Options>
</GetMetadata>
Here is sample output from the request, reformatted for readability:
<Tree Id="A5MFRU33.AI0001JM" TemplateName="MyTree" Name="Untitled" 
Desc="" PublicType="Folder">
<Members>
<ClassifierMap Id="A5MFRU33.BI000001" Name="Test" Desc="" PublicType="StoredProcess" 
IsActive="1" IsUserDefined="0" TransformRole="StoredProcess">
<ComputeLocations>
<ServerContext Id="A5MFRU33.AV000001" Name="SASApp"/>
</ComputeLocations>
<Prompts>
<PromptGroup Id="A5MFRU33.BJ000001" Name="Parameters"/>
</Prompts>
</ClassifierMap>
<Job Id="A5MFRU33.BF0000RT" Name="DailyJob" Desc="" PublicType="Job" IsActive="1" 
IsUserDefined="0" TransformRole="">
<JobActivities>
<TransformationActivity Id="A5MFRU33.BH0000RT" Name="New Transformation Activity"
 Desc="">
<Steps>
<TransformationStep Id="A5MFRU33.BK000001" Name="SAS Splitter" Desc=""/>
<TransformationStep Id="A5MFRU33.BK000002" Name="Transpose" Desc=""/>
<TransformationStep Id="A5MFRU33.BK000003" Name="DateTime_ISO8601conv" Desc=""/>
</Steps>
</TransformationActivity>
</JobActivities>
<TransformationSources/>
<TransformationTargets/>
</Job>
<PhysicalTable Id="A5MFRU33.B50007PU" Name="ACCOUNT_CLOSE_REASON" Desc="" 
PublicType="Table" IsCompressed="0" DBMSType="REMOTE">
<Columns>
<Column Id="A5MFRU33.B600099J" Name="PROCESSED_DTTM" Desc="The timestamp 
for the last time a record was processed, typically by ETL load processing, 
but could also be updated when inter ETL cycle modifications are made to 
a record." SASColumnType="N" SASColumnLength="8" SASFormat="NLDATM21." 
SASInformat=""/>
<Column Id="A5MFRU33.B600099K" Name="CLOSE_REASON_CD" Desc="" SASColumnType="C" 
SASColumnLength="3" SASFormat="" SASInformat=""/>
<Column Id="A5MFRU33.B600099L" Name="VALID_FROM_DTTM" Desc="" SASColumnType="N" 
SASColumnLength="8" SASFormat="NLDATM21." SASInformat=""/>
</Columns>
<Indexes>
<Index Id="A5MFRU33.B70007PV" Name="XPKACCOUNT_CLOSE_REASON" Desc="" 
IndexName="XPKACCOUNT_CLOSE_REASON" IsClustered="0" IsUnique="1"/>
<Index Id="A5MFRU33.B70007PW" Name="CLOSE_REASON_CD" Desc="" IndexName="" 
IsClustered="0" IsUnique="1"/>
</Indexes>
<UniqueKeys>
<UniqueKey Id="A5MFRU33.B80007PV" Name="XPKACCOUNT_CLOSE_REASON" Desc=""/>
<UniqueKey Id="A5MFRU33.B80007PW" Name="XAK1ACCOUNT_CLOSE_REASON" Desc=""/>
</UniqueKeys>
</PhysicalTable>
<Document Id="A5MFRU33.BC0003UX" Name="note for column"/>
<Document Id="A5MFRU33.BC0003UY" Name="rating.Note"/>
</Members>
</Tree>
The request returns information about one stored process, one job, one table, and all requested information for each object. In addition, it returns two Document objects that are in the folder.
The following is an example of a GetMetadataObjects request that uses the new template form. The request sets the OMI_GET_METADATA (256) and OMI_TEMPLATES (4) flags, which are required to activate templates processing in GetMetadataObjects. This request specifies to list tables that have columns that are not numeric that have indexes defined for them, and requests attributes for the columns and indexes. The NOT logical operator in the Search attribute is new in SAS 9.3. For more information about the NOT logical operator, see NOT Logical Operator in AttributeCriteria Component.
<GetMetadataObjects>
<Reposid>A0000000.A5TJRDIT</Reposid>
<Type>PhysicalTable</Type>
<Objects/>
<Ns>SAS</Ns>
<Flags>260</Flags>
<Options>
<Templates>
<Template TemplateName="PhysicalTable">
<PhysicalTable Name="">
<Columns Search="Column[Not(@SASColumnType='N')]">
<Column Match="Column[Indexes/Index]"/>
<Column TemplateExpand="No"/> 
</Columns>
<Indexes/>
</PhysicalTable>
<Column SASColumnName="" SASColumnType="" SASColumnLength="">
 <Indexes/>
</Column>
<Index IndexName="" IsClustered="" IsNoMiss="" IsUnique=""/>
</Template>
</Templates>
</Options>
</GetMetadataObjects>
Here is sample output from the request, reformatted for readability:
<GetMetadataObjects>
<Reposid>A0000000.A5TJRDIT</Reposid>
<Type>PhysicalTable</Type>
<Objects >
   <PhysicalTable Id="A5TJRDIT.B2000001" Name="ODSSTYLE">
   <Columns SEARCH="Column[Not(@SASColumnType='N')]">
   <Column Id="A5TJRDIT.B7000001"/> 
   <Column Id="A5TJRDIT.B7000002"/> 
   </Columns>
   <Indexes/> 
   </PhysicalTable>
   <PhysicalTable Id="A5TJRDIT.B2000002" Name="AUTO">
   <Columns SEARCH="Column[Not(@SASColumnType='N')]">
   <Column Id="A5TJRDIT.B7000003"/> 
   </Columns>
   <Indexes/> 
   </PhysicalTable >
   <PhysicalTable Id="A5TJRDIT.B2000003" Name="CENSUS">
   <Columns SEARCH="Column[Not(@SASColumnType='N')]">
   <Column Id="A5TJRDIT.B700000A" SASColumnName="State" SASColumnType="C" 
SASColumnLength="14">
   <Indexes >
   <Index Id="A5TJRDIT.BI000001" IndexName="State" IsClustered="0" 
IsNoMiss="0" IsUnique="1"/> 
   </Indexes>
   </Column>
   <Column Id="A5TJRDIT.B700000B"/> 
   </Columns>
   <Indexes>
   <Index Id="A5TJRDIT.BI000001"/> 
   </Indexes>
   </PhysicalTable>
   <PhysicalTable Id="A5TJRDIT.B2000004" Name="CENSUS1990">
   <Columns SEARCH="Column[Not(@SASColumnType='N')]">
   <Column Id="A5TJRDIT.B700000E"/> 
   <Column Id="A5TJRDIT.B700000F"/> 
   </Columns>
   <Indexes/> 
   </PhysicalTable>
 <PhysicalTable Id="A5TJRDIT.B200000K" Name="EMPLOYEE">
   <Columns SEARCH="Column[Not(@SASColumnType='N')]">
   <Column Id="A5TJRDIT.B700002R" SASColumnName="EMPNO" SASColumnType="C" 
SASColumnLength="5">
   <Indexes>
   <Index Id="A5TJRDIT.BI000006" IndexName="EMPNO" IsClustered="0" IsNoMiss="0" 
IsUnique="1"/> 
   </Indexes>
   </Column>
   <Column Id="A5TJRDIT.B700002S"/> 
   <Column Id="A5TJRDIT.B700002T"/> 
   <Column Id="A5TJRDIT.B700002U"/> 
   </Columns>
   <Indexes>
   <Index Id="A5TJRDIT.BI000006"/> 
   </Indexes>
   </PhysicalTable>
 <PhysicalTable Id="A5TJRDIT.B200000J" Name="EMPINFO">
   <Columns SEARCH="Column[Not(@SASColumnType='N')]">
   <Column Id="A5TJRDIT.B700002A"/> 
   <Column Id="A5TJRDIT.B700002B"/> 
  </Columns>
   <Indexes>
   <Index Id="A5TJRDIT.BI000003"/> 
   </Indexes>
   </PhysicalTable>
 </Objects>
<Ns>SAS</Ns>
<Flags>260</Flags>
<Options>
<Templates>
<Template TemplateName="PhysicalTable">
<PhysicalTable Name="">
<Columns Search="Column[Not(@SASColumnType=''N'')]">
<Column Match="Column[Indexes/Index]" TemplateName="column"/>
<Column TemplateExpand="No"/> 
</Columns>
<Indexes/>
</PhysicalTable>
</Template>
<Template TemplateName="column">
<Column SASColumnName="" SASColumnType="" SASColumnLength="">
 <Indexes>
  <Index TemplateName="index"/>
 </Indexes>
</Column>
</Template>
<Template TemplateName="index">
<Index IndexName="" IsClustered="" IsNoMiss="" IsUnique=""/>
</Template>
</Templates>
</Options>
</GetMetadataObjects>
The results return information about six tables. Only two of the tables have character columns that have indexes. Column objects for which only Id values are shown are character columns that do not have indexes. Indexes for which only Id values are shown indicate an index that is associated with the table, rather than defined on a character column.

Templates and the OMI_INCLUDE_SUBTYPES Flag

In both the legacy form and the new form, the order of the additional templates that request associations of associated objects is not important, unless the OMI_INCLUDE_SUBTYPES (16) flag is set.
When processing a metadata object, the SAS Metadata Server searches the metadata types listed in the <TEMPLATES> element or the <TEMPLATE> subelement to find a type match for that object. If a match is found, that metadata property string determines the specified attributes and associations to return. If the OMI_INCLUDE_SUBTYPES flag is not specified, an exact type match is required. This exact-match requirement makes the order of the metadata property strings in the template unimportant.
When the OMI_INCLUDE_SUBTYPES flag is specified, the server searches the metadata types just as before, but the conditions for the type match are different. With OMI_INCLUDE_SUBTYPES, the object being processed matches a metadata property string if the object type exactly matches, or if it is a subtype of a metadata property string’s type. Once either type of match is made, the search stops. Any remaining matching property strings are ignored. Therefore, if there are metadata property strings for any supertype in a template, they should be listed after any metadata property strings that are subtypes of that supertype.
The OMI_INCLUDE_SUBTYPES flag does not affect selecting named templates. A named template is always a direct match.

Templates and the OMI_NOEXPAND_DUPS Flag

The SAS Metadata Model defines two association names for every relationship in the SAS Metadata Model. For example, a table object has a Columns association with its Column objects, and a Column object has a Table association with its table. When using templates to expand the associations of associated objects, avoid specifying both sides of a relationship in the template. The server has logic that prevents visiting the same object more than once when a two-sided reference occurs. However, when multiple associations refer to the same metadata types, the server can revisit those same objects over and over again.
This can happen easily in templates that expand objects of the PhysicalTable, Column, and ForeignKey metadata types, which are related to each other through the Columns/Table, ForeignKeys/Table, and Keys/KeyedColumns associations.
To prevent objects from being revisited, you can set the OMI_NOEXPAND_DUPS (524288) flag. However, this flag has memory overhead associated with it, so it is better to avoid specifying two-sided references.
An example of the incorrect way to expand PhysicalTable, Column, and ForeignKey objects is the following:
<PhysicalTable>
   <Columns/>
   <Keys/>
</PhysicalTable>
<Column>
  <Table/>
  <ForeignKeys/>
</Column>
<ForeignKey>
  <Table/>
  <KeyedColumns/>
</ForeignKey>
The correct way to expand them is the following:
<PhysicalTable>
   <Columns/>
</PhysicalTable>
<Column>
 <ForeignKey/>
</Column>