Jose L Martinez-Avial
Jose L Martinez-Avial

Reputation: 2265

xpath get matches in sublist

I've got the following xml:

    <vo class="GroupEntry" buildByAlias="true">
        <objectClass name="groupOfNames"/>
        <field name="commonName"          nameLDAP="cn"          type="String"/>
        <field name="descriptione"         nameLDAP="description"          type="String"/>
        <field name="member"              nameLDAP="member"               type="String[]"/>
    </vo>
    <update method="addMember" modificationMode="ADD_ATTRIBUTE">
        <input>
            <field name="member"/>        
            <field name="description"/>        
        </input>
    </update>

I'm using XSLT to transform it, and I'm need, for each update, to get the fields in the vo that correspond to the field defined in the input. It would be something like this:

<xsl:variable name="fields" select="vo/field" />
<xsl:for-each select="update">
    <xsl:variable name='fieldsForInput' select = "$fields[@name]=input/fields[@name]"/>
    <xsl:for-each select="$fieldsForInput">
       <xsl:value-of select="@type"/> <xsl:value-of select="@name"/>
    <xsl:for-each>
</xsl:for-each>

But it doesn't found anything. Any ideas?

Thanks

JL

Upvotes: 1

Views: 720

Answers (2)

Emiliano Poggi
Emiliano Poggi

Reputation: 24826

From the shown fragments it's difficult helping you and understadning what you want. However your case seems perfect for using xsl:key.

For example, if you create a key at the beginning of the transform like this:

<xsl:key name="fields" match="vo/field" use="@name"/>

You can use it inside your matching template as follows:

        <xsl:for-each select="update/input">
            <xsl:copy-of select="key('fields',current()/field/@name)"/>
        </xsl:for-each>

I would not use a xsl:foreach anyway. But it's hard to give you a complete solution if you provide only fragments. Also is not clear if you want just match or replace field.


Example showing how to get the field name/type for each update/input/field.

XSLT 1.0 tested with Saxon 6.5.5

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="fields" match="vo/field" use="@name"/>

 <xsl:template match="/root">
     <xsl:apply-templates select="update"/>
 </xsl:template>

 <xsl:template match="update">
     <xsl:value-of select="concat('-',@method,'&#xA;')"/>
     <xsl:apply-templates select="input/field"/>
 </xsl:template>

 <xsl:template match="input/field">
    <xsl:value-of select="concat('--',@name,' ',key('fields',@name)/@type,'&#xA;')"/>
 </xsl:template>

</xsl:stylesheet>

Applied on:

<root>
    <vo class="GroupEntry" buildByAlias="true">
        <objectClass name="groupOfNames"/>
        <field name="commonName"          nameLDAP="cn"          type="String"/>
        <field name="description"         nameLDAP="description"          type="String"/>
        <field name="member"              nameLDAP="member"               type="String[]"/>
    </vo>
    <update method="addMember" modificationMode="ADD_ATTRIBUTE">
        <input>
            <field name="member"/>        
            <field name="description"/>        
        </input>
    </update>
        <update method="deleteMember" modificationMode="DELETE_ATTRIBUTE">
        <input>
            <field name="member"/>        
            <field name="description"/>        
        </input>
    </update>
</root>

Produces:

-addMember
--member String[]
--description String
-deleteMember
--member String[]
--description String

Upvotes: 1

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243549

Two solutions:

Solution1 (no keys):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match=
  "vo/field[@name=../../update/*/*/@name]">

  <xsl:value-of select="concat(@name,' ',@type,'&#xA;')"/>
 </xsl:template>
</xsl:stylesheet>

When applied on the provided XML document (corrected to be made well-formed):

<t>
    <vo class="GroupEntry" buildByAlias="true">
        <objectClass name="groupOfNames"/>
        <field name="commonName" nameLDAP="cn" type="String"/>
        <field name="description" nameLDAP="description" type="String"/>
        <field name="member" nameLDAP="member" type="String[]"/>
    </vo>
    <update method="addMember" modificationMode="ADD_ATTRIBUTE">
        <input>
            <field name="member"/>
            <field name="description"/>
        </input>
    </update>
</t>

the wanted, correct result is produced:

description String
member String[]

Solution2 (using a key):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kFieldByName" match="vo/field"
  use="@name"/>

 <xsl:template match="/*">
  <xsl:apply-templates mode="selected" select=
    "key('kFieldByName', update/*/*/@name)"/>
 </xsl:template>

 <xsl:template match="vo/field" mode="selected">
  <xsl:value-of select="concat(@name,' ',@type,'&#xA;')"/>
 </xsl:template>
</xsl:stylesheet>

when applied on the same XML document (above), the same correct result is produced:

description String
member String[]

Upvotes: 0

Related Questions