如果属性值高于阈值,则 XSLT 删除数据

XSLT remove data if attribute value is higher than threshold

我是 XSLT 的新手。我是根据某个字段从 XML 中删除元素,如果它高于我将作为参数获取的某个阈值。

我的XML如下图:

<tns:PM objectClass="MyNode" objectName="" className="com.project.converter.PMFamilyConverter" interfaceName="ComponentPM"
    xmlns:tns="http://www.myproject/SS/PMSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.myProject.com/SS/PM.xsd">
  <tns:family desc="family0" id="f0" eventNumber="000000">
    <tns:performanceIndicator desc="Description 1" id="Success" eventNumber="000001" />
    <tns:performanceIndicator desc="Description 2" id="Error" eventNumber="000002" />
  </tns:family>
  <tns:family desc="family1" id="f1" eventNumber="010000">
    <tns:performanceIndicator desc="Description 1" id="Success" eventNumber="010001" />
    <tns:performanceIndicator desc="Description 2" id="Name Error" eventNumber="010002" />
    <tns:performanceIndicator desc="Description 3" id="Server Not Found Error" eventNumber="010003" />
  </tns:family>
  <tns:family desc="family2" id="f2" eventNumber="020000">
    <tns:performanceIndicator desc="Description 1" id="Success" eventNumber="020001" />
    <tns:performanceIndicator desc="Description 2" id="Format Error" eventNumber="020002" />
    <tns:performanceIndicator desc="Description 3" id="Logic Error" eventNumber="020003" />
    <tns:performanceIndicator desc="Description 4" id="Success with warning message" eventNumber="020004" />
  </tns:family>
  <tns:family desc="family3" id="f3" eventNumber="030000">
    <tns:performanceIndicator desc="Description 1" id="Success" eventNumber="030001" />
    <tns:performanceIndicator desc="Description 2" id="Error" eventNumber="030002" />
  </tns:family>
</tns:PM>

根据网上的一些示例,我编写的 XSL 是:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" standalone="no" indent="yes"/>
<xsl:param name="maxEventNum"/>
<xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
</xsl:template>
    <xsl:template match="/">
      <xsl:apply-templates select="/*[contains(local-name(),'PM')]/*[contains(local-name(),'family')]/@eventNumber"/>
      <xsl:if test="number(.) < $maxEventNum">
            <xsl:copy-of select="/*[contains(local-name(),'PM')]/*[contains(local-name(),'family')]"/>
      </xsl:if>
    </xsl:template>
</xsl:stylesheet>

如果我将 maxEventNumber 作为 020004 传递,我想要的输出如下所示。

<tns:PM objectClass="MyNode" objectName="" className="com.project.converter.PMFamilyConverter" interfaceName="ComponentPM"
    xmlns:tns="http://www.myproject/SS/PMSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.myProject.com/SS/PM.xsd">
  <tns:family desc="family0" id="f0" eventNumber="000000">
    <tns:performanceIndicator desc="Description 1" id="Success" eventNumber="000001" />
    <tns:performanceIndicator desc="Description 2" id="Error" eventNumber="000002" />
  </tns:family>
  <tns:family desc="family1" id="f1" eventNumber="010000">
    <tns:performanceIndicator desc="Description 1" id="Success" eventNumber="010001" />
    <tns:performanceIndicator desc="Description 2" id="Name Error" eventNumber="010002" />
    <tns:performanceIndicator desc="Description 3" id="Server Not Found Error" eventNumber="010003" />
  </tns:family>
</tns:PM>

另外,请问apply-template什么时候用,怎么用,如果match里用apply-template,跟match有关系吗?

第一件事:你应该在你的输入XML中使用 namespace/s,而不是用像*[contains(local-name(),'...')]这样尴尬的表达方式围着他们转。

现在,排除特定节点的最简单方法是从 identity transform 模板(如您所用)开始复制所有节点作为规则,然后添加一个空模板匹配要作为例外排除的节点。

但是,当您要排除的节点由参数确定时,这将不起作用,因为模板的匹配模式不能包含对变量的引用。在这种情况下,您可以使模板的 content 成为条件:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tns="http://www.myproject/SS/PMSchema">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:param name="maxEventNum" select="020004"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="tns:family">
    <xsl:if test="@eventNumber &lt; $maxEventNum">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

注意:(1)添加的xmlns:tns="http://www.myproject/SS/PMSchema"命名空间声明和tns:前缀的使用,以及(2)转义< 运算符为 &lt;.


另一种解决方案将确保模板仅应用于满足条件的 tns:family 个节点:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tns="http://www.myproject/SS/PMSchema">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:param name="maxEventNum" select="020004"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="/tns:PM">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="tns:family[@eventNumber &lt; $maxEventNum]"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

假设-基于预期输出XML-您想要在family及其后代元素f.eperformanceIndicator元素中评估eventNumber属性, 您可以尝试以下 XSLT :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tns="http://www.myproject/SS/PMSchema">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" standalone="no" indent="yes"/>
<xsl:strip-space elements="*"/>
  <xsl:param name="maxEventNum" select="020004"/>
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
  </xsl:template>
  <xsl:template match="/tns:PM/tns:family">
    <xsl:if test="count(.//@eventNumber[number(.) &gt;= $maxEventNum]) = 0">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()" />
      </xsl:copy>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>
  • 第一个模板是标识模板,它匹配所有节点和属性并将它们复制到输出 XML,因为它在源 XML.
  • 第二个模板覆盖了匹配元素的身份模板 - family 元素在这种情况下 -;更具体的模板会覆盖更通用的模板。此模板测试 eventNumber 属性 当前上下文 family 中的值是否 等于或高于 阈值(您 隐含地声明当阈值本身为020004时,eventNumber=020004应该从输出中移除。如果有 none 这样的 eventNumber 属性 (count(...)=0),复制当前 family 元素到输出,否则不要 copy/do nothing.