tags:

views:

612

answers:

2

Using this file as source, I have a situation where I need to retrieve an element from either the local source file or a related one noted in the imports. The type value uses a colon to separate the two values - substring-before(@type, ':') tells me which file to reference; substring-after(@type, ':') is the name of the element in the file I need to copy & iterate over its contents in the same fashion.

Example: I want the xs:complexType where the name is "PersonType", so I use the copy-of to grab it and its children. The next step is to look at those children - for those that are xs:element, I want to retrieve the element referenced in the type value ("AcRec:HighSchoolType"). The "AcRec" tells me which xsd I need to use, so I know I'll find something in that xsd where the name value is "HighSchoolType". Looking at the AcRec xsd, I know that "HighSchoolType" is an xs:complexType (which I already have a template defined to handle) so I should see the output.

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;
<xsl:template match="/">
<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">
 <xsl:apply-templates select="//xs:complexType[@name='PersonType']" />    
</xs:schema>
</xsl:template> 

<xsl:template match="xs:complexType">
 <xsl:copy>
  <xsl:copy-of select="node()[not(xs:annotation | xs:restriction)]|@*"/>
 </xsl:copy>
 <xsl:apply-templates select=".//xs:element" />
</xsl:template>

<xsl:template match="xs:simpleType">
 <xsl:copy>
  <xsl:copy-of select="node()|@*"/>
 </xsl:copy>
</xsl:template> 

<xsl:template match="xs:element">
 <xsl:choose>
  <xsl:when test="substring-before(@type, ':') = 'AcRec'">
   <xsl:text>AcRec</xsl:text>
   <xsl:apply-templates select="document('[local file path]AcademicRecord_v1.3.0.xsd')//*[@name=substring-after(@type, ':')]" />
  </xsl:when>                     
 </xsl:choose>
</xsl:template>

Desired output would look like:

<xs:complexType name="PersonType">
  <xs:sequence>
 <xs:element name="HighSchool" type="AcRec:HighSchoolType" minOccurs="0">
  </xs:sequence>
</xs:complexType>
<xs:complexType name="HighSchoolType">
  <xs:sequence>
 <xs:element name="OrganizationName" type="core:OrganizationNameType"/>
 <xs:group ref="core:OrganizationIDGroup" minOccurs="0"/>
  </xs:sequence>
</xs:complexType>

What am I missing about looking within the document when I successfully enter the xsl:when? The xsl:text tells me I'm in, but the subsequent line returns no output.

Additionally, how do I exclude xs:annotation and xs:restriction elements from appearing when copying the xs:complextType & xs:simpleType elements? I haven't been able to get the examples mentioned on the dpawson site to work.

A: 

I have to say, and take no offense, that your question is really difficult to understand; could you break it down a little more?

Meanwhile, as far as excluding xs:annotation and xs:restriction elements, just change your copy-of statement to leave them out:

<xsl:copy-of select="node()[not(self::xs:annotation or self::xs:restriction)]|@*"/>

... and you have an xsl:choose element with only one xsl:when and no xsl:otherwise... you could simplify this with an xsl:if element:

<xsl:template match="xs:element">
   <xsl:if test="substring-before(@type, ':') = 'AcRec'">
     <xsl:text>AcRec</xsl:text>
       <xsl:apply-templates select="document('[local file path]AcademicRecord_v1.3.0.xsd')//*[@name=substring-after(@type, ':')]" />
   </xsl:if>
</xsl:template>

Upon further reflection, it looks like your select statement might be malformed: currently it is trying to match any element that has a name attribute that matches the type attribute after the colon. So a match would have to be

<element name="text" type="some:text"/>

If you don't have an element like this, then your match is empty, so no templates are run.

ScottSEA
I updated the post to include an example - hopefully it's more clear. I didn't have any lucky with the exclusion you suggested - would it matter if there are children associated with the annotation/restriction elements?
OMG Ponies
I need it to match <element name="text" /> rather than <element name="text" type="some:text"/>. I interpreted the CHOOSE to catch the various instances of "some" in the current so that I knew to use some.xsd to look for element name="text".
OMG Ponies
yeah... I forgot the self:: axis in the annotation/restriction segment. Revised appropriately.
ScottSEA
A: 

The issue was:

<xsl:apply-templates select="document('[local file path]AcademicRecord_v1.3.0.xsd')//*[@name=substring-after(@type, ':')]" />

...should be:

<xsl:variable name="name" select="substring-after(@type, ':')" />
<xsl:apply-templates select="document('[local file path]AcademicRecord_v1.3.0.xsd')//*[@name=$name]" />

ScottSEA - you were correct when you said it was comparing based on:

<element name="text" type="some:text"/>

What happens is that there is a context switch involved in the processing of that XPath expression. When you say //*[@name=substring-after(@type, ':')], you say "apply this template to those elements in the XSD document referenced, that have both a @name and a @type attribute, and whose @name is equal to substring-after ':' of THEIR @type. Whereas, if you use a variable, you of course get the substring-after from the current document.

OMG Ponies