使用自定义标记语言过滤XML数据

时间:2012-05-20 21:10:40

标签: xml xslt xpath xml-parsing

我正在尝试编写一个文档,该文档可以帮助过滤来自另一个XML文档的数据。例如。

<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>

我希望这段代码能够首先选择属于足球俱乐部成员的用户,然后选择那些单身用户。但我无法弄清楚如何为此编写样式表。我写了这个:

<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>

在调用模板时,我会传递正确的值。

问题是我获得所有单身用户以及该特定群组成员的所有用户。但是我想要也是足球俱乐部成员的单身用户。我不希望样式表被硬编码,因为我也想基于其他元素进行过滤。

我无法弄清楚如何将过滤后的元素保存为可用作下一个XPath表达式输入的内容。或者我在编写过滤文档的约束时犯了一些错误。或者是否有其他更合适的方式来编写文档进行过滤?我将非常感谢你的帮助。

1 个答案:

答案 0 :(得分:1)

使用:

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

基于XSLT的验证:

<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>

在提供的XML文档上应用此转换时(更正了一些拼写错误):

<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>

评估上述XPath表达式,并将选定的节点(在本例中只是一个节点)复制到输出

<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>