tags:

views:

36

answers:

1

Very simply, is it possible to type an XSLT template or function to return a named sequence constructor?

e.g. in FpML, there is the Product.model group, which simply contains two elements (ProductType and ProductId). I'd like to be able to create a typed template which returns that sequence, but have no idea what the "as" attribute should contain.

Update

I'll include the relevant bit of the FpML schema for convenience :

<xsd:group name="Product.model">
<xsd:sequence>
  <xsd:element name="productType" type="ProductType" minOccurs="0" maxOccurs="unbounded">
    <xsd:annotation>
      <xsd:documentation xml:lang="en">A classification of the type of product. FpML defines a simple product categorization using a coding scheme.</xsd:documentation>
    </xsd:annotation>
  </xsd:element>
  <xsd:element name="productId" type="ProductId" minOccurs="0" maxOccurs="unbounded">
    <xsd:annotation>
      <xsd:documentation xml:lang="en">A product reference identifier allocated by a party. FpML does not define the domain values associated with this element. Note that the domain values for this element are not strictly an enumerated list.</xsd:documentation>
    </xsd:annotation>
  </xsd:element>
</xsd:sequence>

So, I'd like to be able to type a template as this xsd:group. Is this even possible?

+1  A: 

The value of the @as should contain an XPATH sequence type

Since you are constructing a sequence of two different types of elements I believe you would use element()*, which would indicate that the template will return zero or more occurrences of an element.

You could type the individual templates/functions used to produce those elements and restrict them to the specific element. For intance, element(ProductType)? would indicate zero or one ProductType element.

<xsl:template name="ProductModel" as="element()*">
  <xsl:call-template name="ProductType" />
  <xsl:call-template name="ProductId" />
</xsl:template>

<xsl:template name="ProductType" as="element(ProductType)?">
  <ProductType></ProductType>
</xsl:template>

<xsl:template name="ProductId" as="element(ProductId)?">
  <ProductId></ProductId>
</xsl:template>

EDIT: looking over the details for sequence type syntax, the definition of element is:

ElementTest ::= "element" "(" (ElementNameOrWildcard ("," TypeName "?"?)?)? ")"

The second parameter, type name, is a QName

One of the examples listed under 2.5.3 SequenceType Syntax:

element(*, po:address) refers to an element node of any name that has the type annotation po:address (or a type derived from po:address)

So, you might be able to do the following(but it would probably require a schema aware processor, like Saxon-EE):

<xsl:template name="ProductModel" as="element(*,fpml:Product.model)*">
  <xsl:call-template name="ProductType" />
  <xsl:call-template name="ProductId" />
</xsl:template>

<xsl:template name="ProductType" as="element(ProductType)?">
  <ProductType></ProductType>
</xsl:template>

<xsl:template name="ProductId" as="element(ProductId)?">
  <ProductId></ProductId>
</xsl:template>
Mads Hansen
The '+' indicates 'one or more'. If you want to indicate 'zero or one' you need to use '?'.
Martin Honnen
whoops! Thanks @Martin Honnen. I've updated the code sample.
Mads Hansen
This is an interesting way to organise the code, but it doesn't really solve the problem, since the ProductModel template is only very broadly typed. What I'd like to have in the @as is something like "element(*, fpml:Product.model)", but I can't find anything to suggest this is even possible.
inferis
That might be possible. I added some details about the sequence type syntax that indicates it might be.
Mads Hansen
We're using Saxon-EE anyway, so the requirement for a schema-aware processor isn't a problem. Unfortunately, I have tried almost exactly what you've suggested, and Saxon throws an error. Whether it *should* or not, I don't know. I suspect the fact that an ElementTest expects a QName should tell me that it's behaving correctly, but this seems like a hole in the spec to me.
inferis