XSLT 节点相等匹配一切

XSLT node equality matching everything

我有一个 XML 文件,例如:

<?xml version="1.0" encoding="ISO-8859-1"?>
<list>
    <report file="onefile.xml" oneAttr="2123as"></report>
    <report file="myfile.xml" oneAttr="blabla"></report>
    <report file="myfile.xml" oneAttr="2123as"></report>
    <report file="another.xml" oneAttr="2123as"></report>
</list>     <!-- changed by edit -->

而且我需要一个样式表,它可以在 @file="myfile.xml" 的最后一场比赛之后添加一个新的报告元素。

到目前为止我得到了什么:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

<xsl:template match="/list">
    <list>
    <xsl:variable name="insertAfter" select="report[@file='myfile.xml'][last()]"/>
    <xsl:for-each select="report">
        <xsl:copy-of select="."/>
        <xsl:text>&#xA;</xsl:text>
        <xsl:if test="current() = $insertAfter">
            <report file="newFile.xml"></report>
        </xsl:if>
        <xsl:text>&#xA;</xsl:text>
    </xsl:for-each>
    </list>
</xsl:template>

上面的 XSLT 不工作,相等比较似乎没有按预期工作并且正在匹配所有报告,因此每次都添加新的节点元素。我假设它可能不检查属性的相等性,而只检查其中为空的文本。

我知道在 XSLT 2.0 中有这个 "eq" 运算符,它可能正在做我想要的,但我想坚持使用 XSLT 1.0。

有什么解决方案的建议吗?

您的口头描述 'last match of @file="myfile.xml"' 翻译成

<xsl:template match="report[@file = 'myfile.xml'][last()]">
  <xsl:call-template name="identity"/>
  <report file="newFile.xml"></report>
</xsl:template>

所以你似乎只需要

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

  <xsl:output method="xml" indent="yes"/>

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

    <xsl:template match="report[@file = 'myfile.xml'][last()]">
      <xsl:call-template name="identity"/>
      <report file="newFile.xml"></report>
    </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/gWmuiJU

存在 XSLT 2 中的节点身份检查,但将使用 is 运算符而不是 eq 来完成。但是你也不需要它。

您可以通过使用 generate-id(...) function 创建 last() 节点的唯一 ID 并匹配它来实现:

<xsl:template match="/list">
    <list>
    <xsl:variable name="insertAfter" select="generate-id(report[@file='myfile.xml'][last()])"/>
    <xsl:for-each select="report">
        <xsl:copy-of select="."/>
        <xsl:text>&#xA;</xsl:text>
        <xsl:if test="generate-id(current()) = $insertAfter">
            <report file="newFile.xml"></report>
        </xsl:if>
        <xsl:text>&#xA;</xsl:text>
    </xsl:for-each>
    </list>
</xsl:template>

输出:

<?xml version="1.0"?>
<list>
    <report file="onefile.xml" oneAttr="2123as"/>    
    <report file="myfile.xml" oneAttr="blabla"/>    
    <report file="myfile.xml" oneAttr="2123as"/>
    <report file="newFile.xml"/>
    <report file="another.xml" oneAttr="2123as"/>    
</list>