0

I am having trouble with the following test (xpath) in an xsl document:

<xsl:if test="document('../resourcefiles/users.xml')/users/user[email=$email]/*[name()= current()/../../@id] = current()/@value">
    <xsl:attribute selected="true"></xsl:attribute>
</xsl:if>

The xsl document (below) is building a form with form elements defined in one xml document (registry.xml) filling the form elements in with data of a certain user in another xml document (users.xml). The 'registry.xml' is subject to changes, so it is not known what elements the form will contain, only that they will comply to the same structure as the ones in the current registry.xml. This works well except for one type of form elements: form elements of the type 'select'. The test above is supposed to select the user from users.xml with the email equal to $email (/users/user[email=$email])and then match the value of the property saved for the user in users.xml with the correct option value fetched from registry.xml (/users/user[email=$email]/*[name()= current()/../../@id] = current()/@value). When the test is true, the xsl adds an attribute (selected="true") to the option in question.

I think I am doing something wrong in the xpath test, but I just cannot wrap my head around it.

The xml documents are registry.xml (where info on the structure of 'users' and their properties is found):

<?xml version="1.0" encoding="UTF-8"?>
<registry>
   <objects>
    <user created="dd.mm.yy" lastactive="dd.mm.yy" status="1">
        <attribute>
            <name>created</name>
        </attribute>
        <attribute>
            <name>lastactive</name>
        </attribute>
        <attribute>
            <name>status</name>
        </attribute>
        <property type="checkbox" id="administrator" status="99" mandatory="false" securitysetting="99" sortorder="6" unique="false">
            <name>Site Administrator</name>
        </property>
        <property type="text" id="name" status="1" mandatory="true" securitysetting="1" sortorder="0" unique="false">
            <name>Full Name</name>
        </property>
        <property type="email" id="email" status="1" mandatory="true" securitysetting="1" sortorder="1" unique="true">
            <name>Email</name>
        </property>
        <property type="text" id="password" status="1" mandatory="true" securitysetting="1" sortorder="2" unique="false">
            <name>Password</name>
        </property>
        <property type="select" id="animal" status="1" securitysetting="99" mandatory="false" sortorder="5" unique="false">
            <name>Animal</name>
            <options>
                <option value="monkey">Monkey</option>
                <option value="horse">Horse</option>
                <option value="lion">Lion</option>
            </options>
        </property>
        <property type="text" id="phone" status="1" securitysetting="1" mandatory="false" sortorder="3" unique="false">
            <name>Phone</name>
            <options/>
        </property>
        <property type="checkbox" id="checkbox" status="1" securitysetting="1" mandatory="false" sortorder="4" unique="false">
            <name>Checkbox</name>
            <options/>
        </property>
    </user>
   </objects>
</registry>

And users.xml:

<?xml version="1.0"?>
<users>
 <user created="14.02.16" lastactive="never" status="1">
  <administrator>true</administrator>
  <name>Tom Hanks</name>
  <email>th@aficdd.at</email>
  <password>tham</password>
  <animal>monkey</animal>
  <phone>+43123123</phone>
  <checkbox>false</checkbox>
 </user>
 <user created="15.02.16" lastactive="never" status="1">
  <administrator>false</administrator>
  <name>Navn Navnesen</name>
  <email>asdf@gmail.com</email>
  <password>asdf</password>
  <animal>horse</animal>
  <phone>+43987987</phone>
  <checkbox>true</checkbox>
 </user>
 <user created="16.02.16" lastactive="never" status="0">
  <administrator>false</administrator>
  <name>Deaktiveret Bruger</name>
  <email>deactive@asdfasdf.cs</email>
  <password>deactive</password>
  <animal>lion</animal>
  <phone>+4435345</phone>
  <checkbox>false</checkbox>
 </user>
</users>

The xsl document is:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="email"/>


<xsl:template match="/">

<br/>
<form action="javascript:validateEdituserForm()">
<table>

    <xsl:for-each select="document('../resourcefiles/registry.xml')/registry/objects/user/property[@status != '0']">
        <xsl:sort order="ascending" select="@sortorder"/>

        <tr>
            <td><p class="loginform"><xsl:value-of select="./name"/><xsl:if test="@mandatory = 'true'">*</xsl:if>:</p></td>
            <td>
            <xsl:choose>
                <!-- property is a select element -->
                <xsl:when test="@type = 'select'">
                    <select>
                        <xsl:attribute name="name"><xsl:value-of select="@id"/></xsl:attribute>
                        <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
                        <xsl:attribute name="class">autoproperty<xsl:if test="@mandatory = 'true'"> mandatory</xsl:if></xsl:attribute>
                        <xsl:attribute name="onchange">javascript:addUserFormChange(this.id);</xsl:attribute>
                        <xsl:for-each select="./options/option">
                            <option>
                                <xsl:attribute name="value"><xsl:value-of select="@value"/></xsl:attribute>
<!-- HERE IS MY PROBLEM -->
                                <xsl:if test="document('../resourcefiles/users.xml')/users/user[email=$email]/*[name()= current()/../../@id] = current()/@value"><xsl:attribute name="selected">true</xsl:attribute></xsl:if>
<!-- ABOVE IS MY PROBLEM -->
                                <xsl:value-of select="name"/>
                            </option>
                        </xsl:for-each>
                    </select>
                </xsl:when>
                <!-- property is a checkbox -->
                <xsl:when test="@type = 'checkbox'">
                    <input>
                        <xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute>
                        <xsl:attribute name="name"><xsl:value-of select="@id"/></xsl:attribute>
                        <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
                        <xsl:attribute name="class">autoproperty<xsl:if test="@mandatory = 'true'"> mandatory</xsl:if></xsl:attribute>
                        <xsl:attribute name="onkeyup">javascript:addUserFormChange(this.id);</xsl:attribute>
                        <xsl:if test="document('../resourcefiles/users.xml')/users/user[email=$email]/*[name()= current()/@id] = 'true'"><xsl:attribute name="checked">true</xsl:attribute></xsl:if>
                    </input>
                </xsl:when>
                <!-- property is any other type -->
                <xsl:otherwise>
                    <input>
                        <xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute>
                        <xsl:attribute name="name"><xsl:value-of select="@id"/></xsl:attribute>
                        <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
                        <xsl:attribute name="class">autoproperty<xsl:if test="@mandatory = 'true'"> mandatory</xsl:if></xsl:attribute>
                        <xsl:attribute name="onkeyup">javascript:addUserFormChange(this.id);</xsl:attribute>
                        <xsl:attribute name="value"><xsl:value-of select="document('../resourcefiles/users.xml')/users/user[email=$email]/*[name()= current()/@id]"/></xsl:attribute>
                    </input>
                </xsl:otherwise>
            </xsl:choose>
            </td>
            <td><p class="formalert"><xsl:attribute name="id"><xsl:value-of select="@id"/>alert</xsl:attribute></p></td>
        </tr>
    </xsl:for-each>
 <tr>
  <td><p class="loginform">&#160;</p></td>
  <td></td>
  <td></td>
 </tr>
 <tr>
  <td><p class="loginform">Notify user per email:</p></td>
  <td><input class="autoproperty" type="checkbox" name="notifyuser" id="notifyuser" onclick="javascript:notifyuserclicked();"/></td>
  <td><p class="formalert" id="notifyuseralert"></p></td>
 </tr>
 <tr>
  <td><input type="button" class="button" onclick="javascript:newClearFormElements();"><xsl:attribute name="value"><xsl:value-of select="document('../resourcefiles/lang/labels.xml')/labels/label[@id = 'labelbuttonclearform']/value"/></xsl:attribute></input></td>
  <td><input type="submit" class="button"><xsl:attribute name="value"><xsl:value-of select="document('../resourcefiles/lang/labels.xml')/labels/label[@id = 'labelbuttonsavechanges']/value"/></xsl:attribute></input></td>
 </tr>
</table>
<p class="formalert" id="edituseralertarea"></p>
</form>

</xsl:template>

</xsl:stylesheet>
Tim C
  • 70,053
  • 14
  • 74
  • 93
Sune S.-T.
  • 235
  • 2
  • 15

1 Answers1

1

Finally found out. For reasons I do not quite understand, the xpath test had to be changed from:

test="document('../resourcefiles/users.xml')/users/user[email=$email]/*[name()= current()/../../@id] = current()/@value"

into:

test="document('../resourcefiles/users.xml')/users/user[email=$email]/*[name()= current()/../../@id] = @value"

I still do not know why current()/@value does not work and @value does, but it works.

Sune S.-T.
  • 235
  • 2
  • 15
  • Finally understood it thanks to this old post written by Paul A. Jungworth: http://stackoverflow.com/questions/1022345/current-node-vs-context-node-in-xslt-xpath. While current()/@value refers to the value of the node being processed, @value refers to the context node. – Sune S.-T. Mar 16 '16 at 11:39