【问题标题】:XSLT node equality matching everythingXSLT 节点相等匹配一切
【发布时间】:2018-09-27 20:00:58
【问题描述】:

我有一个 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。

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

【问题讨论】:

  • 为了清楚一点,使用“=”运算符比较两个节点是比较它们的字符串值,并且所有报表元素的字符串值都是零长度字符串,所以它们都是相等的。

标签: xml xslt xslt-1.0 transformation


【解决方案1】:

您的口头描述“@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。但无论如何你都不需要它。

【讨论】:

    【解决方案2】:

    您可以通过使用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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多