?
Solved

Using XSL to create dynamic dropdown menus

Posted on 2003-03-07
11
Medium Priority
?
964 Views
Last Modified: 2010-05-19
I want to create a pair of nested dynamic dropdown menus from a XML doc.  I am willing to double the amount of points for this question if someone can give me a specific example of what I need.

I have two menus one for locations, and one for customers.  The second menu list values are dependant on the value of the first menu.

My idea is that once the location box is changed, it fires of some JavaScript (insert your help here) that uses Path (more help please) to get the child nodes below the id of selected location.  The JavaScript would then transform the new DOM object created from the XPath statement using XSL (help) to render the customers select box using some type of innterHtml inside a div.

The xml doc looks something like:

<sites>
     <location name="site 1" id="1">
          <customer name="cust 1" id="11">
               <host name="host 1" id="111"/>
               <host name="host 1" id="112"/>
               <host name="host n" id="11n"/>
          </customer>
          <customer name="cust n" id="1a1">
               <host name="host 1" id="11a1"/>
               <host name="host 1" id="1s12"/>
               <host name="host n" id="1s1n"/>
          </customer>
     </location>
     <location name="site n" id="n">
          <customer name="cust 1" id="11">
               <host name="host 1" id="111"/>
               <host name="host 1" id="112"/>
               <host name="host n" id="11n"/>
          </customer>
          <customer name="cust n" id="1a1">
               <host name="host 1" id="11a1"/>
               <host name="host 1" id="1s12"/>
               <host name="host n" id="1s1n"/>
          </customer>
     </location>
</sites>
0
Comment
Question by:makman111
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
11 Comments
 
LVL 28

Expert Comment

by:sybe
ID: 8090423
Is it for IE 5+ only ? Because then you can easy use XSL for this. I am not sure which (other) browsers support Javascript for XSL.
0
 

Author Comment

by:makman111
ID: 8090708
Yes
0
 
LVL 14

Expert Comment

by:avner
ID: 8096784
<html>
<head>
<title>about:blank</title>
<script language="javascript1.2">
<!-- copyright(c) avcoh@yahoo.com


var oXML = null;

function createSelect(obj,sIDEffected)
{
     var oTarget = document.forms['formName'].elements[sIDEffected];

     var sValue = obj.options[obj.options.selectedIndex].value;
     var oList = oXML.selectSingleNode("//location[@id='"+sValue+"']");
     if (oList)
          {
               addOptions(oTarget, oList.childNodes);
          }
}

function addOptions(oSelect, oChildNodes)
{
var iLen = oSelect.options.length;
     for (var i=0;i<iLen;i++)
          {
               oSelect.options[0] = null;
          }
var iLen = oChildNodes.length;
     for (var i=0;i<iLen;i++)
          {
               oSelect.options[oSelect.options.length]= new Option(oChildNodes[i].getAttribute("name"),oChildNodes[i].getAttribute("id"));
          }

}


function init()
{
     oXML = document.getElementById("data");

     addOptions(document.getElementById("location"), oXML.selectSingleNode("/sites").childNodes);
     document.getElementById("location").options[0].selected="true";
     document.getElementById("location").fireEvent("onchange");
     //createSelect(document.getElementById("location"),"customer", "1");
}

-->
</script>
</head>
<body onload="init()">
<form id="formName">
Location :
<select name="location" onchange="createSelect(this,'customer')">
</select><br/>

Customer:
<select name="customer">
</select>
</form>



<xml id="data">
<sites>
    <location name="site 1" id="1">
         <customer name="Customer!" id="11">
              <host name="host 1" id="111"/>
              <host name="host 1" id="112"/>
              <host name="host n" id="11n"/>
         </customer>
         <customer name="Customer!!!!" id="1a1">
              <host name="host 1" id="11a1"/>
              <host name="host 1" id="1s12"/>
              <host name="host n" id="1s1n"/>
         </customer>
    </location>
    <location name="site n" id="n">
         <customer name="cust 1" id="11">
              <host name="host 1" id="111"/>
              <host name="host 1" id="112"/>
              <host name="host n" id="11n"/>
         </customer>
         <customer name="cust n" id="1a1">
              <host name="host 1" id="11a1"/>
              <host name="host 1" id="1s12"/>
              <host name="host n" id="1s1n"/>
         </customer>
    </location>
</sites>
</xml>
</body>
</html>
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 9

Accepted Solution

by:
sparkplug earned 2000 total points
ID: 8097185
Hi,

Here's an XSLT version:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<!-- These are the params for specifying the locationid and customerid for the default selection in each dropdown list box-->
<xsl:param name="DefaultSelectedLocationID" select="string(/sites/location[1]/@id)" />
<xsl:param name="DefaultSelectedCustomerID" select="string(/sites/location[@id=$SelectedLocationID]/customer[1]/@id)" />

<!-- These are the variable for storing the locationid and customerid for the current selection in each dropdown list box-->
<xsl:variable name="SelectedLocationID" select="$DefaultSelectedLocationID" />
<xsl:variable name="SelectedCustomerID" select="$DefaultSelectedCustomerID" />

<xsl:template match = "/">
<html>
  <head>
  <script type = "text/javascript" language = "javascript">
      <![CDATA[
         var oXSLDoc = document.XSLDocument;
         var oXMLDoc = document.XMLDocument;
      
      //Updates XSL variable
         function updateVar(sName, sValue)
         {
              //select the xsl:variable node. This is for storing the item selected in each drop down list
              var oVarNodeSelectAttr = oXSLDoc.selectSingleNode( "//xsl:variable[@name='" + sName + "']/@select" );
            
            
            //reset to default or store the selected value
              if (sValue == '_default')
                     oVarNodeSelectAttr.nodeValue = "$Default" + sName;
            else
                    oVarNodeSelectAttr.nodeValue = "string('" + sValue + "')";

         
         }
         
         //retransform the current XML document with the current XSL document
         function reDisplay()
         {
              //we only want to transform from the root node. This is so we dont repeat the headers and script sections
             divResults.innerHTML = oXMLDoc.documentElement.transformNode( oXSLDoc );

         }
      ]]>
    </script>
    </head>
   <body>
      <div ID = "divResults">
             <!-- This is a place holder for the dropdown lists which will by replaced with the above javascript -->
         <xsl:apply-templates select="sites"/>
      </div>
   </body>
</html>

</xsl:template>

<xsl:template match = "sites">
      Location:
      <select name="LocationList" onchange="updateVar('SelectedLocationID', this.value);updateVar('SelectedCustomerID', '_default');reDisplay()">
            <xsl:apply-templates select="location">
                  <xsl:sort select="@name"/>
            </xsl:apply-templates>
      </select>
      <br/>
      <br/>
      Customer:
      <select name="CustomerList" onchange="updateVar('SelectedCustomerID', this.value);reDisplay()">
            <xsl:apply-templates select="location[@id = $SelectedLocationID]/customer">
                  <xsl:sort select="@name"/>
            </xsl:apply-templates>
      </select>

      <br/>
      <br/>
      <table border="1">
      <tr><th>host</th><th>host id</th></tr>
            <xsl:apply-templates select="location[@id = $SelectedLocationID]/customer[@id = $SelectedCustomerID]/host">
                  <xsl:sort select="@name"/>
            </xsl:apply-templates>
      </table>
 
   
</xsl:template>

<xsl:template match = "location">
      <option>
            <xsl:attribute name="value">
                 <xsl:value-of select="@id"/>
            </xsl:attribute>
            <xsl:if test="@id = $SelectedLocationID">
               <xsl:attribute name="selected">selected</xsl:attribute>
            </xsl:if>
            <xsl:value-of select="@name"/>
      </option>
</xsl:template>


<xsl:template match = "customer">
      <option>
            <xsl:attribute name="value">
                 <xsl:value-of select="@id"/>
            </xsl:attribute>
            <xsl:if test="@id = $SelectedCustomerID">
               <xsl:attribute name="selected">selected</xsl:attribute>
            </xsl:if>
            <xsl:value-of select="@name"/>
      </option>
</xsl:template>

<xsl:template match = "host">
      <tr>
            <td><xsl:value-of select="@name"/></td>
            <td><xsl:value-of select="@id"/></td>
      </tr>
</xsl:template>

</xsl:stylesheet>


Put the filename at the top of the XML to get this to work e.g. <?xml:stylesheet type="text/xsl" href="dropdown.xslt"?>

>S'Plug<
0
 

Author Comment

by:makman111
ID: 8098372
I keep geeting a javascript error.

'oXSLDoc is undefined' in the line

var oVarNodeSelectAttr = oXSLDoc.selectSingleNode( "//xsl:variable[@name='" + sName + "']/@select" );
0
 

Author Comment

by:makman111
ID: 8098919
Okay fixed the javascript (I was actually using the wrong XML doc), but It does not seem to be re-building the doc.  

>S'Plug<

Can you contact me direct via e-mail?  jmaki@makman.net
0
 
LVL 9

Expert Comment

by:sparkplug
ID: 8099264
Hi,

When you say that it is not rebuilding the doc, do you mean that the second drop down list is not being updated when the first drop down list is changed? What XML file are you using to test this? The example above contains several repeated names so the changes might not be apparent? I tested this on IE6 before posting it but not any other browser. I would expect it to work in IE5.5 but not IE5.

>S'Plug<

0
 

Author Comment

by:makman111
ID: 8099280
I think I got it figured out...   Is there any way to do this so that the customer box is rendered sperately than the locaiton box?

This way I can have two different <div> tags at different locations?
0
 

Author Comment

by:makman111
ID: 8099285
Also,

How do I make the default option "Choose One"

Thanks
0
 
LVL 9

Expert Comment

by:sparkplug
ID: 8099428
I'm not sure what you mean by seperating the two boxes. You can have two different <div>s as in the following extract. In fact you can put whatever HTML tags you like into this template. You could for example change the order or put them in a table.

<xsl:template match = "sites">
<div id="divLocation">
     Location:
     <select name="LocationList" onchange="updateVar('SelectedLocationID', this.value);updateVar('SelectedCustomerID', '_default');reDisplay()">
          <option value="-1">Choose One</option>
          <xsl:apply-templates select="location">
               <xsl:sort select="@name"/>
          </xsl:apply-templates>
     </select>
</div>

     <br/>
     <br/>

<div id="divCustomer">
     Customer:
     <select name="CustomerList" onchange="updateVar('SelectedCustomerID', this.value);reDisplay()">
          <option value="-1">Choose One</option>          <xsl:apply-templates select="location[@id = $SelectedLocationID]/customer">
               <xsl:sort select="@name"/>
          </xsl:apply-templates>
     </select>
</div>

     <br/>
     <br/>
     <table border="1">
     <tr><th>host</th><th>host id</th></tr>
          <xsl:apply-templates select="location[@id = $SelectedLocationID]/customer[@id = $SelectedCustomerID]/host">
               <xsl:sort select="@name"/>
          </xsl:apply-templates>
     </table>
 
 
</xsl:template>


To make the default option "Choose One", add "<option value="-1">Choose One</option>" to each select box as shown above. Also change the default params at the top of the file as follows:

<!-- These are the params for specifying the locationid and customerid for the default selection in each dropdown list box-->
<xsl:param name="DefaultSelectedLocationID" select="string(-1)" />
<xsl:param name="DefaultSelectedCustomerID" select="string(-1)" />

>S'Plug<
0
 
LVL 9

Expert Comment

by:sparkplug
ID: 8099446
Sorry that should be:

<option value="-1">
<xsl:if test="$SelectedLocationID = -1">
    <xsl:attribute name="selected">selected</xsl:attribute>
</xsl:if>
Choose One
</option>

e.g.

  Location:
    <select name="LocationList" onchange="updateVar('SelectedLocationID', this.value);updateVar('SelectedCustomerID', '_default');reDisplay()">
        <option value="-1">
        <xsl:if test="$SelectedLocationID = -1">
        <xsl:attribute name="selected">selected</xsl:attribute>
        </xsl:if>
         Choose One
         </option>
         <xsl:apply-templates select="location">
              <xsl:sort select="@name"/>
         </xsl:apply-templates>
    </select>


>S'Plug<
0

Featured Post

DFW AZURE MEETUP TONIGHT FRI 6PM

We will be discussing what Azure Stack is, how does it fit into the suit of offerings that Azure has currently, and where can it fit into your organizations technology stack. We will also be discussing limitations of the platform while covering various applicable scenarios.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction In my previous article (http://www.experts-exchange.com/Microsoft/Development/MS-SQL-Server/SSIS/A_9150-Loading-XML-Using-SSIS.html) I showed you how the XML Source component can be used to load XML files into a SQL Server database, us…
Create a Windows 10 custom Image with custom task bar and custom start menu using XML for deployment.
Monitoring a network: how to monitor network services and why? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the philosophy behind service monitoring and why a handshake validation is critical in network monitoring. Software utilized …
Do you want to know how to make a graph with Microsoft Access? First, create a query with the data for the chart. Then make a blank form and add a chart control. This video also shows how to change what data is displayed on the graph as well as form…
Suggested Courses
Course of the Month12 days, 5 hours left to enroll

752 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question