我是XSLT的新手,我昨天开始阅读它并且我被卡住了。我有以下XML
<?xml version="1.0" encoding="utf-8" ?>
<Menu>
<Function>
<Name>ViewHome</Name>
<Roles>
<Role>Finance</Role>
<Role>Advisor</Role>
<Role>Admin</Role>
</Roles>
</Function>
<Function>
<Name>ViewStaff</Name>
<ChildFunctions>
<Function>
<Name>StaffFunction1</Name>
<Roles>
<Role>Finance</Role>
</Roles>
</Function>
<Function>
<Name>StaffFunction2</Name>
<Roles>
<Role>Admin</Role>
</Roles>
</Function>
<Function>
<Name>StaffFunction3</Name>
<Roles>
<Role>Advisor</Role>
</Roles>
</Function>
</ChildFunctions>
</Function>
<Function>
<Name>ViewDiary</Name>
<Roles>
<Role>Advisor</Role>
</Roles>
</Function>
</Menu>
我希望转换为仅显示包含指定角色的那些函数(父级或子级)。因此,如果应用财务和顾问角色,则输出将如下:
<?xml version="1.0" encoding="utf-8" ?>
<Menu>
<Function>
<Name>ViewHome</Name>
<Roles>
<Role>Finance</Role>
<Role>Advisor</Role>
</Roles>
</Function>
<Function>
<Name>ViewStaff</Name>
<ChildFunctions>
<Function>
<Name>StaffFunction1</Name>
<Roles>
<Role>Finance</Role>
</Roles>
</Function>
<Function>
<Name>StaffFunction3</Name>
<Roles>
<Role>Advisor</Role>
</Roles>
</Function>
</ChildFunctions>
</Function>
<Function>
<Name>ViewDiary</Name>
<Roles>
<Role>Advisor</Role>
</Roles>
</Function>
</Menu>
我查看了此网站上的其他帖子,但无法生成所需的输出。我一直在使用的xsl是:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" />
<xsl:variable name="rolesList">Advisor Finance</xsl:variable>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Function[not(descendant::Role[contains($rolesList, .)])]"/>
<!--
<xsl:template match="Function[not(descendant::Role='Finance')]"/>
-->
</xsl:stylesheet>
最终,rolesList变量将通过代码提供。我只是想让变换工作。如果我将注释掉的模板匹配用于“财务”角色,我会得到预期的结果。 非常感谢任何帮助。
答案 0 :(得分:1)
使用XSLT 1.0使用字符串比较,您可以使用
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" />
<xsl:param name="roleList" select="'|Advisor|Finance|'"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Function">
<xsl:if test="descendant::Role[contains($roleList, concat('|', ., '|'))]">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
<xsl:template match="Role">
<xsl:if test="contains($roleList, concat('|', ., '|'))">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
使用内部查找列表:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="your-urn-here">
<my:rolesList>
<my:role>Advisor</my:role>
<my:role>Finance</my:role>
</my:rolesList>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Function[not(descendant::Role = document('')/*/my:rolesList/my:role)]"
/>
</xsl:stylesheet>
答案 2 :(得分:0)
我怀疑如果有多个Role
元素,则contains()无法正常工作,因为该函数不希望将列表作为其第二个参数。
请注意,您将角色列表提供为以空格分隔的列表。但是,如果没有Schema,则不会将其识别为列表类型。这就是为什么你必须依赖字符串函数,正如@ michael.hor257k所指出的那样。
这个(即包含变量的模板匹配)仅适用于XSLT 2.0,正如@Tim C所指出的那样。
使用以下样式表:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="roles">Finance Advisor</xsl:variable>
<xsl:template match="Function[count(Roles/Role) = 1 and not(matches($roles,Roles/Role))]"/>
<xsl:template match="Role[not(matches($roles,.))]"/>
</xsl:stylesheet>
<强>输出强>
<?xml version="1.0" encoding="UTF-8"?>
<Menu>
<Function>
<Name>ViewHome</Name>
<Roles>
<Role>Finance</Role>
<Role>Advisor</Role>
</Roles>
</Function>
<Function>
<Name>ViewStaff</Name>
<ChildFunctions>
<Function>
<Name>StaffFunction1</Name>
<Roles>
<Role>Finance</Role>
</Roles>
</Function>
<Function>
<Name>StaffFunction3</Name>
<Roles>
<Role>Advisor</Role>
</Roles>
</Function>
</ChildFunctions>
</Function>
<Function>
<Name>ViewDiary</Name>
<Roles>
<Role>Advisor</Role>
</Roles>
</Function>
</Menu>
答案 3 :(得分:0)
我希望转换为仅显示那些功能(父母或 child)包含指定的角色。
我相信你的样式表就是这样(虽然它不应该,但只有一些处理器 - 请参阅问题的评论以获取更多详细信息)。
然而,不从已经通过测试的函数的后代角色列表中删除“其他”角色。为此,您需要添加另一个与Role匹配的模板。
最终,rolesList变量将通过代码
提供
理想情况下,列表将作为节点集(或可以转换为节点集的东西)提供,这样您就可以进行比较而无需求助于字符串函数。但是,在XSLT 2.0中,这方面有更多的灵活性。