tags:

views:

230

answers:

3

I have the XSD content in this file.

Using this xsl, I can copy the contents of the desired element:

<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:template match="node()|@*" name="copy">
 <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
 </xsl:copy>
</xsl:template>

<xsl:template match="xs:complexType">
 <xsl:call-template name="copy"/>
</xsl:template>

<xsl:template match="xs:element">
 <xsl:choose>
  <xsl:when test="contains(@type, 'core')">
   core
  </xsl:when>
  <xsl:when test="contains(@type, 'AcRec')">
   AcRec
  </xsl:when>   
 </xsl:choose>
</xsl:template>

The idea is to select a particular node in an xsd, and generate all the supporting elements into a single file by looking them up based on the type value.

The desired output should ultimately look like:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:core="urn:org:pesc:core:CoreMain:v1.2.0" xmlns:AcRec="urn:org:pesc:sector:AcademicRecord:v1.1.0">
<xs:complexType name="PersonType">
 <xs:sequence>
  <xs:element name="SchoolAssignedPersonID" type="core:SchoolAssignedPersonIDType" minOccurs="0"/>
  <xs:element name="SIN" type="core:SINIDType" minOccurs="0"/>
  <xs:element name="NSN" type="core:NSNIDType" minOccurs="0"/>
  <xs:element name="AgencyAssignedID" type="core:AgencyAssignedIDType" minOccurs="0"/>
  <xs:element name="RecipientAssignedID" type="core:RecipientAssignedIDType" minOccurs="0"/>
  <xs:element name="SSN" type="core:SSNType" minOccurs="0"/>
  <xs:element name="Birth" type="core:BirthType" minOccurs="0"/>
  <xs:element name="Name" type="core:NameType"/>
  <xs:element name="AlternateName" type="core:NameType" minOccurs="0" maxOccurs="unbounded"/>
  <xs:element name="HighSchool" type="AcRec:HighSchoolType" minOccurs="0" />
  <xs:element name="Contacts" type="AcRec:ContactsType" minOccurs="0" maxOccurs="unbounded"/>
  <xs:element name="Gender" type="core:GenderType" minOccurs="0"/>
  <xs:element name="Residency" type="AcRec:ResidencyType" minOccurs="0"/>
  <xs:element name="Deceased" type="core:DeceasedType" minOccurs="0"/>
  <xs:element name="NoteMessage" type="core:NoteMessageType" minOccurs="0" maxOccurs="unbounded"/>  
 </xs:sequence>
</xs:complexType>
<xs:simpleType name="SchoolAssignedPersonIDType" />
<xs:simpleType name="SINIDType" />
<xs:simpleType name="NSNIDType" />
<xs:simpleType name="AgencyAssignedIDType" />
<xs:complexType name="HighSchoolType">
 <xs:sequence>
  <xs:element name="OrganizationName" type="core:OrganizationNameType"/>
  <xs:element name="OPEID" type="core:OPEIDType"/>
  <xs:element name="NCHELPID" type="core:NCHELPIDType"/>
  <xs:element name="IPEDS" type="core:IPEDSType"/>
  <xs:element name="ATP" type="core:ATPType"/>
  <xs:element name="FICE" type="core:FICEType"/>
  <xs:element name="ACT" type="core:ACTType"/>
  <xs:element name="CCD" type="core:CCDType"/>
  <xs:element name="CEEBACT" type="core:CEEBACTType"/>
  <xs:element name="CSIS" type="core:CSISType"/>
  <xs:element name="USIS" type="core:USISType"/>
  <xs:element name="ESIS" type="core:ESISType"/>
  <xs:element name="DUNS" type="core:DUNSType"/>
 </xs:sequence>
</xs:complexType>
<xs:simpleType name="OrganizationNameType" />
<xs:simpleType name="OPEIDType" />

The idea I was was to use a combination of templates - the copy first to grab the element & sub-elements (exluding xs:annotations and xs:restrictions). The second template would iterate over the xs:element contents of an element to retrieve the reference from the other file. Additionally, when xs:groups are encountered, the xs:group ref element is to be replaced with the contents of the element in the xs:group definition.

A: 

You cannot "force" it to use a template with a match attribute. Such template will apply to all elements that match it, and only to those elements. So if some of those child elements that matched node() are complexType, it will be applied automatically.

You can give it a name, of course, and then use <xsl:call-template name="...">.

Pavel Minaev
A: 

You can use

<xsl:apply-templates select="complexType"/>
<xsl:apply-templates select="node()[local-name() != 'complexType']|@*"/>

This will output all complex nodes before the rest. Alternatively, to change the order, you need to do:

<xsl:apply-templates select="node()[local-name() != 'complexType']|@*"/>
<xsl:apply-templates select="complexType"/>
Rashmi Pandit
+1  A: 

This is a bit of a shot in the dark, but I think you are missing the correct handling of namespaces in your XSL stylesheet.

The "complexType" template you made does not match the "xs:complexType" nodes have. You must declare the xs namespace, like this:

<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
>

and you must use it, too:

<xsl:template match="xs:complexType">
  <!-- ... -->
</xsl:template>

<xsl:template match="xs:element">
  <!-- ... -->
</xsl:template>

Once I made that change, your stylesheet gave me:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;
  <xs:complexType name="PersonType">
    <xs:sequence>core core core core core core core core core AcRec AcRec core AcRec core core</xs:sequence>
  </xs:complexType>
</xs:schema>

Which clearly shows that the template is being used. XSL always uses the most specific template it can find for any given node, just like CSS uses the most specifc rule it can find.

The <xsl:template match="node()|@*"> is a lot less specific than the <xsl:template match="complexType">, but unless you use the xs namespace, the latter just does not match anything.

P.S.: A few remarks:

  • <xsl:otherwise> is not mandatory, you can leave it out if it is empty.
  • there is no need to use <xsl:call-template name="copy" />. Once you define what output you'd like to see, we can get rid of that in favor of a cleaner approach
  • as your <xsl:when> tests I'd recommend substring-before(@type, ':') = 'core' over contains(@type, 'core'). The latter is more error-prone.
  • it is probably just for of the example, but you should use <xsl:text>core</xsl:text> to avoid unnecessary whitespace in the output.
Tomalak
Thanks - I've been struggling with this, and really appreciate the help.