Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filtering XML data using custom markup language

I am trying to write a document which could help in filtering data from another XML document. E.g.

<document>
    <filter>
        <what>
            <include>
                <marital_staus/>
                <ms>single</ms> <!--nog = no of groups-->
                <include>
                    <memberofgroups/>
                    <gn>Football club</gn> <!--user is a member of this club-->
                </include>
            </include>
        </what>
    </filter>

    <users>
            <user>
                <name>
                    <first>abc</first>
                    <last>xyz</last>
                </name>
                <dob>12/02/1987</dob>
                <marital_status>married</marital_status>
                <groups>
                    <member_of_group>Chess Club</member_of_group>
                    <member_of_group>Football club</member_of_group>
                </groups>
            </user>

            <user>
                <name>
                    <first>aaa</first>
                    <last>bbb</last>
                </name>
                <dob>14/03/1987</dob>
                <marital_status>single</marital_status>
                <groups>
                    <member_of_group>Chess Club</member_of_group>
                    <member_of_group>Football club</member_of_group>
                </groups>
            </user>

             <user>
                <name>
                    <first>fff</first>
                    <last>nnn</last>
                </name>
                <dob>12/6/1983</dob>
                <marital_status>single</marital_status>
                <groups>
                    <member_of_group>Chess Club</member_of_group>
                    <member_of_group>Cultural Association</member_of_group>
                </groups>
            </user>
     </users>
</document>

What I want this code to do is to choose, first, the users who are members of Football club, and then out of those, chose the users who are single. But I cannot figure out how to write a stylesheet for this. I wrote this:

<xsl:template name="temp">
        <xsl:param name="a1"/>
        <xsl:param name="pro"/>
        <xsl:choose>
            <xsl:when test="$pro = 'marital_status'">
                <xsl:for-each select="/document/users/user">
                    <xsl:if test="marital_status=$a1">
                        <xsl:value-of select="."/>
                    </xsl:if>                
                </xsl:for-each>
            </xsl:when>
            <xsl:when test="$pro = 'memberofgroups'">
            <xsl:for-each select="/document/users/user">
                <xsl:for-each select="./groups/member_of_group">
                    <xsl:if test=".=$a1">
                        <xsl:value-of select="."/>
                    </xsl:if>
                </xsl:for-each>
            </xsl:for-each>
        </xsl:when>
        </xsl:choose>
    </xsl:template>
<xsl:template match="include">
        <xsl:call-template name="temp">
            <xsl:with-param name="a1">
                <xsl:apply-templates select="*[2]"/>
            </xsl:with-param>
        </xsl:call-template>
    </xsl:template>

While calling the template I pass the correct values I suppose.

Problem is I get all the users who are single, plus all the users who are members of that particular group. However I want single users who are also member of Football club. I don't want the stylesheet to be hard-coded, because I also want to do filtering based on other elements.

I can not figure out how can I save the filtered elements into something which could be used as an input for the next XPath expression. Or am I making some mistake while writing the constraints for filtering the document. Or could there be any other more appropriate way of writing a document for filtering? I will much appreciate your help.

like image 332
ashamim Avatar asked Feb 01 '26 06:02

ashamim


1 Answers

Use:

   /*/*/user
     [*[name() = name(/*/filter/*/include/*[1])]
     =
      /*/filter/*/include/*[2]
     and
      groups/*[name() = name(/*/filter/*/include/include/*[1])]
     =
      /*/filter/*/include/include/*[2]
     ]

XSLT - based verification:

<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="/">
     <xsl:copy-of select=
      "/*/*/user
         [*[name() = name(/*/filter/*/include/*[1])]
         =
          /*/filter/*/include/*[2]
         and
          groups/*[name() = name(/*/filter/*/include/include/*[1])]
         =
          /*/filter/*/include/include/*[2]
         ]
"/>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document (with a few typos corrected):

<document>
    <filter>
        <what>
            <include>
                <marital_status/>
                <ms>single</ms>
                <!--nog = no of groups-->
                <include>
                    <member_of_group/>
                    <gn>Football club</gn>
                    <!--user is a member of this club-->
                </include>
            </include>
        </what>
    </filter>
    <users>
        <user>
            <name>
                <first>abc</first>
                <last>xyz</last>
            </name>
            <dob>12/02/1987</dob>
            <marital_status>married</marital_status>
            <groups>
                <member_of_group>Chess Club</member_of_group>
                <member_of_group>Football club</member_of_group>
            </groups>
        </user>
        <user>
            <name>
                <first>aaa</first>
                <last>bbb</last>
            </name>
            <dob>14/03/1987</dob>
            <marital_status>single</marital_status>
            <groups>
                <member_of_group>Chess Club</member_of_group>
                <member_of_group>Football club</member_of_group>
            </groups>
        </user>
        <user>
            <name>
                <first>fff</first>
                <last>nnn</last>
            </name>
            <dob>12/6/1983</dob>
            <marital_status>single</marital_status>
            <groups>
                <member_of_group>Chess Club</member_of_group>
                <member_of_group>Cultural Association</member_of_group>
            </groups>
        </user>
    </users>
</document>

the above XPath expression is evaluated and the selected nodes (in this case just a single node) are copied to the output:

<user>
   <name>
      <first>aaa</first>
      <last>bbb</last>
   </name>
   <dob>14/03/1987</dob>
   <marital_status>single</marital_status>
   <groups>
      <member_of_group>Chess Club</member_of_group>
      <member_of_group>Football club</member_of_group>
   </groups>
</user>
like image 135
Dimitre Novatchev Avatar answered Feb 04 '26 00:02

Dimitre Novatchev