Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xml XSLT-删除没有与特定值匹配的子节点的节点_Xml_Xslt_Xpath - Fatal编程技术网

Xml XSLT-删除没有与特定值匹配的子节点的节点

Xml XSLT-删除没有与特定值匹配的子节点的节点,xml,xslt,xpath,Xml,Xslt,Xpath,我对XSLT非常陌生,我昨天开始阅读有关它的文章,我被卡住了。我有以下XML <?xml version="1.0" encoding="utf-8" ?> <Menu> <Function> <Name>ViewHome</Name> <Roles> <Role>Finance</Role> <Role>Advisor</Role>

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

观景屋
财务
顾问
管理
视杆
员工职能1
财务
员工职能2
管理
职员职能3
顾问
查看日记
顾问
我希望将其转换为仅显示那些包含指定角色的函数(父函数或子函数)。因此,如果应用财务和顾问角色,则输出将如下所示:

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

观景屋
财务
顾问
视杆
员工职能1
财务
职员职能3
顾问
查看日记
顾问
我看过这个网站上的其他帖子,但无法生成所需的输出。我一直在使用的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变量将通过代码提供。我只是想让转换工作起来。如果我只为“财务”角色使用注释掉的模板匹配,我会得到预期的结果。 非常感谢您的帮助。

如果有多个
Role
元素,我怀疑contains()无法正常工作,因为函数不希望列表作为其第二个参数

请注意,您提供的角色列表是一个以空格分隔的列表。然而,如果没有模式,它就不能被识别为列表类型。正如@michael.hor257k所指出的,这就是为什么必须依赖字符串函数

正如@timc所指出的,这(即包含变量的模板匹配)只适用于XSLT2.0

使用以下样式表:

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

观景屋
财务
顾问
视杆
员工职能1
财务
职员职能3
顾问
查看日记
顾问
我想将其转换为仅显示那些函数(父函数或 包含一个或多个指定角色的

我相信您的样式表确实做到了这一点(,尽管它不应该这样做,而且只针对某些处理器-有关更多详细信息,请参阅问题的注释)

但是,它不会从通过测试的函数的子代角色列表中删除“其他”角色。为此,您需要添加另一个模板匹配角色

最终rolesList变量将通过代码提供


理想情况下,列表将作为节点集(或可以转换为节点集的内容)提供,这样您就可以进行比较,而无需使用字符串函数。但是,在XSLT2.0中,在这方面有更大的灵活性。

在XSLT1.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>

使用内部查找列表:

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

顾问
财务

您能在这里使用XSLT 2.0吗?在XSLT1.0中,不可能在模板匹配中使用变量,但在XLST2.0中是这样。另一方面,在模板匹配中,您指的是roleList,但该变量实际上名为roleList!Tim,我对使用哪个版本的XSL没有限制。感谢您注意到输入错误。您可以指定不应出现在输出中的角色吗?@TimC“在XSLT 1.0中,无法在模板匹配中使用变量。请原谅,我没有正确表达。应该理解为“您不能在
xsl:template
命令的
match
属性中使用变量。”