This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

RE: xslt assistance please


I wholeheartedly agree with the advice for you to buy Michael Kay's book.  I
got it cheap and fast from Buy.com.  You may wish to check for it there
(something like $19, if I remember correctly).

What you posted looked like an interesting problem to me, so I took some
time out to figure out a solution.  In the process, I thought I'd might
learn a little about XML Schemas, which is what your example appears to be
at least a dialect of.  Instead of delving into the actual rules of XSDL, I
induced some implicit rules based on your examples and implemented them in
the stylesheet.  I did this so the stylesheet might apply in more general
cases, rather than just this specific example.  I'm sure that the schema
rules I induced are not complete or entirely correct, so don't rely on this
stylesheet to work for every case.  In particular, ask yourself if a new
example uses something that's not in the example you provided here.  If
that's the case, the stylesheet would have to be modified to include what is
currently unaccounted for.

This stylesheet uses the node-set() function, which converts a result tree
fragment ($rtf) into a node-set containing one root node, enabling you to
access children of that root, etc., with XPath expressions.  I needed to do
so here in order to pass the "derivatives" tree as a parameter from template
to template, using it to determine how given "element" elements should be
copied to the result.  This function is an extension function provided by
Saxon.  To make this stylesheet work with other processors besides Saxon,
simply change the extension's namespace declaration accordingly, as other
processors including XT and Xalan also supply node-set() functions.

This may seem overwhelming, as the problem you provided is not necessarily a
trivial one.  I started simple a few months ago and have since begun to
explore and appreciate some of the real power of XSLT.  If you have any
specific questions about how this stylesheet works, feel free to email me
privately.

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:saxon="http://icl.com/saxon"
  exclude-result-prefixes="saxon">

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:apply-templates select="*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*">
    <xsl:variable name="derived" select="boolean(@base)"/>
    <complexType name="{name()}">
      <xsl:if test="$derived">
        <xsl:copy-of select="@base"/>
        <xsl:attribute name="derivedBy">restriction</xsl:attribute>
      </xsl:if>
      <all>
        <xsl:if test="$derived">
          <xsl:variable name="rtf">
            <xsl:copy-of select="*[not(self::element)]"/>
          </xsl:variable>
          <xsl:apply-templates select="//*[name() = current()/@base]
                                        [1]/element" mode="derived">
            <xsl:with-param name="derivatives"
                                   select="saxon:node-set($rtf)"/>
          </xsl:apply-templates>
        </xsl:if>
        <xsl:apply-templates select="element"/>
      </all>
    </complexType>
  </xsl:template>

  <xsl:template match="element">
    <xsl:copy-of select="."/>
  </xsl:template>

  <xsl:template match="element" mode="derived">
    <xsl:param name="derivatives"/>
    <xsl:variable name="elementName" select="@name"/>
    <xsl:copy>
      <xsl:apply-templates select="@*">
        <xsl:with-param name="derivatives" select="$derivatives"/>
      </xsl:apply-templates>
      <xsl:if test="not(@maxOccurs) and $derivatives/prohibited/*
                                         [name() = $elementName]">
        <xsl:attribute name="maxOccurs">0</xsl:attribute>
      </xsl:if>
      <xsl:variable name="default" select="$derivatives/defaults/*
                                     [name() = $elementName][1]"/>
      <xsl:if test="$default">
        <xsl:attribute name="use">default</xsl:attribute>
        <xsl:attribute name="value">
          <xsl:value-of select="$default/@value"/>
        </xsl:attribute>
      </xsl:if>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="@*">
    <xsl:copy-of select="."/>
  </xsl:template>

  <xsl:template match="@minOccurs">
    <xsl:param name="derivatives"/>
    <xsl:variable name="elementName" select="../@name"/>
    <xsl:choose>
      <xsl:when test="$derivatives/mandatory/*
                        [name() = $elementName] or
                         $derivatives/mandatory/@fields='ALL'">
        <xsl:attribute name="{name()}">1</xsl:attribute>
      </xsl:when>
      <xsl:when test="$derivatives/prohibited/*
                                      [name() = $elementName]">
        <xsl:attribute name="{name()}">0</xsl:attribute>
      </xsl:when>
      <xsl:when test="$derivatives/defaults/*
                                      [name() = $elementName]"/>
      <xsl:otherwise>
        <xsl:copy-of select="."/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="@maxOccurs">
    <xsl:param name="derivatives"/>
    <xsl:variable name="elementName" select="name(..)"/>
    <xsl:choose>
      <xsl:when test="$derivatives/prohibited/*
                                        [name() = $elementName]">
        <xsl:attribute name="{name()}">0</xsl:attribute>
      </xsl:when>
      <xsl:otherwise>
        <xsl:copy-of select="."/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>


Have fun learning XSLT!

Evan Lenz
elenz@xyzfind.com
http://www.xyzfind.com
XYZFind, the search engine *designed* for XML
Download our free beta software: http://www.xyzfind.com/beta





-----Original Message-----
From: owner-xsl-list@mulberrytech.com
[mailto:owner-xsl-list@mulberrytech.com]On Behalf Of Azariah Jeyakumar
Sent: Friday, October 13, 2000 11:24 AM
To: 'XSL-List@mulberrytech.com'
Subject: xslt assistance please


Hi,

Would someone help me get started with XSLT? I need to transform 1.xml to
2.xml.

Thanks a lot
Azariah

1.xml
--------

<root>

<AccountBaseDescriptorType>
  <element name="Name"       type="string"    minOccurs="0" />
  <element name="Medium"     type="string"    minOccurs="0" />
  <element name="Address"    type="string"    minOccurs="0" />
  <element name="Id"         type="Integer64" minOccurs="0" />
  <element name="remaining"  type="string"    minOccurs="0" />
</AccountBaseDescriptorType>

<AccountCreatableDescriptorType base="AccountBaseDescriptorType" >
  <mandatory>
    <Name/>
    <Address/>
  </mandatory>
  <prohibited>
    <Id/>
  </prohibited>
  <defaults>
    <Medium value="TW_MEDIUM_SMTP_HTTP"/>
  </defaults>
</AccountCreatableDescriptorType>

<AccountDescriptorType base="AccountBaseDescriptorType" >
  <mandatory fields="ALL">
  </mandatory>
</AccountDescriptorType>

</root>

2.xml
--------
<complexType name="AccountBaseDescriptorType">
  <all>
    <element name="Name"       type="string"    minOccurs=0 />
    <element name="Medium"     type="string"    minOccurs=0 />
    <element name="Address"    type="string"    minOccurs=0 />
    <element name="Id"         type="Integer64" minOccurs=0 />
    <element name="remaining"  type="string"    minOccurs=0 />
  </all>
</complexType>

<complexType name="AccountCreatableDescriptorType"
base="AccountBaseDescriptorType"
    derivedBy="restriction" >
  <all>
    <element name="Name"       type="string"    minOccurs=1 />
    <element name="Medium"     type="string"    use="default"
        value="TW_MEDIUM_SMTP_HTTP" />
    <element name="Address"    type="string"    minOccurs=1 />
    <element name="Id"         type="Integer64" minOccurs=0 maxOccurs=0 />
    <element name="remaining"  type="string"    minOccurs=0 />
  </all>
</complexType>

<complexType name="AccountDescriptorType" base="AccountBaseDescriptorType"
  derivedBy="restriction" >
  <all>
    <element name="Name"       type="string"    minOccurs=1 />
    <element name="Medium"     type="string"    minOccurs=1 />
    <element name="Address"    type="string"    minOccurs=1 />
    <element name="Id"         type="Integer64" minOccurs=1 />
    <element name="remaining"  type="string"    minOccurs=1 />
  </all>
</complexType>

PS1: My goal is to generate 2.xml. So, it is OK to restructure 1.xml to make
the transformation easier-to-write.
PS2: Performance is not a consideration for the transformation.
PS3: The element names "Account...DescriptorType" should not be hard-coded
in the .xsl file.



 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]