xsl-list
[Top] [All Lists]

Getting a NodeList from a NodeList II (Full Problem Shown with Code)

2003-07-02 01:22:00
OK, I have taken some time below to explain in more detail what I am after now 
:)

THE XML
=======

The XML is essentially a list of employee nodes. Each employee has some 
information and also some date stamped approval information. It's not really 
relevant "what" this is to the problem, but it is holiday stuff. I also have 
some "filter" nodes under the root. This was my solution to passing Query 
String values to the XSL from the ASP page that transforms the XML with XSL. 
More later..

<employees>
  <filterDepartment value="All Staff" /> 
  <filterYear value="2003" /> 
  <filterThreshold value="0" /> 
  <employee username="johnsmith" fullname="John Smith" id="999" 
department="Sales">
    <approvals>
      <approval timestamp="1043884800000" date="30/01/2003" year="2003" 
type="F" requested="1043918289965" diff="-33489965" over4Wks="false" 
isRetro="true" /> 
      <approval timestamp="1043971200000" date="31/01/2003" year="2003" 
type="F" requested="1043918291578" diff="52908422" isRetro="false" 
over4Wks="false" />
    </approvals>
    <allocations>
      <allocation year="2003" days="23" /> 
      <allocation year="2004" days="24" /> 
    </allocations>
  </employee>
</employees>


THE XSL AT THE MOMENT
=====================

The report I am trying to generate is based on department, so I loop over 
unique departments and for each one I get the employees in it and print some 
information. I use a msxml function getDepartments which is my way of getting a 
different set of departments depending on the filterDepartment node value 
(which was a Query String parameter). Now, I do not like using proprietry 
Microsoft behaviours ATALL, but I could not think how else..I suppose maybe a 
choose block but I have several reports that all use the same kind of technqiue 
so I put the function into a separate XSL which I import.

<xsl:for-each select="comp:getDepartments(/)">
  <xsl:sort select="." order="ascending" />
  <xsl:variable name="deptName" select="." />

  <xsl:for-each select="//employee[./@department = $deptName]">
    <xsl:sort select="@fullname" order="ascending" />

    <xsl:value-of select="./@fullname" />
    .. other code
  </xsl:for-each>

</xsl:for-each>

COMP:GETDEPARTMENTS(/) MSXML FUNCTION
=====================================

You will notice comp:getDepartments(/). This is a MSXML function. The reason I 
used this was because the XSL has to be aware of different filters that define 
what the report shows. So, my reporting front end passes in either All Staff, 
Some Staff or a Department name. Depending on what comes in, I have to change 
the node list that are iterated over. So I have this function which I pass the 
root node into and it looks a bit like this..

<msxsl:script language="JScript" implements-prefix="comp">
        
  function getDepartments(nodeList) {

    var dept = 
(nodeList.item(0).selectSingleNode("//filterDepartment")).getAttribute("value");
 

    if(dept == "All Staff") {

      return nodeList.item(0).selectNodes("//employee/@department[not(. = 
preceding::employee/@department)]");

    } else if(dept == "Some Staff") {

      return nodeList.item(0).selectNodes("//employee/@department[not(. = 
preceding::employee/@department) and (" +
          "(. = 'Sales') " +
          "or (. = 'I.T'))]");

    }
        
    return nodeList.item(0).selectNodes("//employee/@department[not(. = 
preceding::employee/@department) and (. = '" + dept + "')]");
  }

</msxml:script>

I could not think of another way to make my XSL "aware" of Query String 
parameters other than to add them as top level "filter" nodes with value 
attributes and then use a function like this.

THE PROBLEM
===========

Remember how for each department I loop over the employees in it with;

  <xsl:for-each select="//employee[./@department = $deptName]">
    <xsl:sort select="@fullname" order="ascending" />

    <xsl:value-of select="./@fullname" />
  </xsl:for-each>

Well, what I want to do is filter the employees brought back depending on some 
time filters I have which define a date range to search within. I want 
therefore to bring back "all employees in the current department where they 
have approvals whose timestamp value (a date in MS) falls between a from date 
filter filterFDate and to date filter filterTDate.

The way I thought about doing this was to send the whole list of employees in 
the department to a function like this..

  <xsl:for-each select="comp:getFilteredEmployees(//employee[./@department = 
$deptName])">
    <xsl:sort select="@fullname" order="ascending" />

    <xsl:value-of select="./@fullname" />
  </xsl:for-each>

BUT this comes into the function as a node list, and I cannot then apply 
another "select" type command on the node list to get another node list to 
return to the call.

MY CURRENT WORKAROUND (IS THIS THE SOLUTION?)
=============================================

I thought about it differently after posting the message and decided to put the 
whole condition that I would have done in the function into the select so that 
I selected all emps in the current dept. that had 1 or more approvals whose 
timestamp falls between the 2 filters.

  <xsl:for-each select="//employee[(./@department = $deptName) and 
(./approvals/approval  [(@timestamp >= $filterFDate) and not (@timestamp > 
$filterTDate)])]">
    <xsl:sort select="@fullname" order="ascending" />

    <xsl:value-of select="./@fullname" />
  </xsl:for-each>

This seems to work fine in actual fact...but, as this is my first outing with 
XSL I would really appreciate some constructive criticism about my problem and 
how I have attempted to solve it and if I could have done things better. 

UPCOMING PROBLEM
================

And shortly, I shall be having to change the report so that you can order by 
not only department but employee name too. At the moment the only way I can 
think of doing that is to create a whole separate XSL sheet for it??

FINALLY
=======

Sorry this is so long. I do hope to hear back from some of you on this!

Allistair.


<FONT SIZE=1 FACE="VERDANA,ARIAL" COLOR=BLUE> 
-------------------------------------------------------
QAS Ltd.
Developers of QuickAddress Software
<a href="http://www.qas.com";>www.qas.com</a>
Registered in England: No 2582055
Registered in Australia: No 082 851 474
-------------------------------------------------------
</FONT>


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



<Prev in Thread] Current Thread [Next in Thread>