Friday, September 21, 2012

XSLT: Extract a Branch from an XML Tree

Often you may wish to extract a portion of an XML file including all of its children elements so as to better deal with it or further transform or handle it elsewhere. 

For example, in web-service-based development, it is common for a developer to “extract” the payload from a request or response envelope.  This can also be in situations where a NIEM developer wishes to obtain the payload portion of a LEXS package and further process, store or display it. 

With XSLT, it only takes the following few lines of code to pull a branch of XML out of a larger package.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:output method="xml" indent="yes"/>
    
    <xsl:template match="/uml">
        <xsl:apply-templates select="XMI" mode="RecursiveDeepCopy" />
    </xsl:template> 
    
    <xsl:template match="@*|node()" mode="RecursiveDeepCopy">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <xsl:apply-templates mode="RecursiveDeepCopy" />
        </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet>

In the above example, the XMI/* elements and attributes are being extracted from the /uml/ container element. Before the transform, the XML would look something like this:

<uml>
  <XMI>
    <XMI.header/>
    <XMI.content/>
  </XMI>
</uml>

And after it would look like this:

<XMI>
  <XMI.header/>
  <XMI.content/>
</XMI>

For information on similar transforms, simply Google or Bing "Identity transforms."

Saturday, September 8, 2012

XSD: Extending Code Lists with xsd:union

In certain circumstances it is necessary to add elements to an existing NIEM enumeration (or code list).  In these situations one may choose to simply recreate a new list with all the same elements already defined in a NIEM code type and simply add those which do not yet exist.  However, when the code list is larger than a few elements (such as a state code list with at least 50 valid values), using xsd:union as an option becomes more appealing.

The xsd:union provides a way to combine simple data types together to form a larger and more comprehensive data type.  An example would be simply adding “ZZ” to a list of US Postal Service State (USPS) Codes to communicate an unknown or invalid state.  This can be accomplished by extending the existing USPS code list in several steps.

Step 1 – Create a New Simple Type With New Values

<!-- Simple code value to add ZZ as a valid value -->
<xsd:simpletype name="USStateCodeDefaultSimpleType">
  <xsd:restriction base="xsd:token">
   <xsd:enumeration value="ZZ">
    <xsd:annotation>
     <xsd:documentation>UNKNOWN</xsd:documentation>
    </xsd:annotation>
   </xsd:enumeration>
  </xsd:restriction>
</xsd:simpletype>

Step 2 – Use xsd:union to Join the Values with Existing Values

<!-- New simple time combining my custom enum with the standard usps one --> 
<xsd:simpleType name="LocationStateCodeSimpleType">
  <xsd:union memberTypes="usps:USStateCodeSimpleType my:USStateCodeDefaultSimpleType"/>
</xsd:simpleType>

Step 3 – Wrap the New Simple Data Type in a Complex Type

<!-- New complexType required to add s:id and s:idref to the definition -->
<xsd:complexType name="LocationStateCodeType">
  <xsd:simpleContent>
    <xsd:extension base="aoc_code:LocationStateCodeSimpleType"> 
      <xsd:attributeGroup ref="s:SimpleObjectAttributeGroup"/>
    </xsd:extension>
  </xsd:simpleContent>
</xsd:complexType>

Step 4 – Create Element Instantiating the New Code List

<!-- Element declaration allowing use of our new data type -->
<xsd:element name="NewStateCode" type="my:LocationStateCodeType" substitutionGroup="nc:LocationStateCode"/>

Now any place an nc:LocationStateCode can be use, our extended code list can be used instead.