微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 foreach 中处理排除的元素

如何解决在 foreach 中处理排除的元素

在第一个模板中,我有意排除了一个元素('milk'),因为解析的数据映射相对平坦,我想使用 XSLT 对数据进行分类结构化。目的是处理第二个模板中排除的元素(“牛奶”)。这两个模板一次运行一个。一起运行模板不会显示排除元素('milk')的结果,该元素应该设置另一个属性名称属性值。

JSON:

<data>
{
  "storage": {
    "pencils": 12,"milk": 8,"rulers": 4
  }
}
</data>

XSL:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:transform
  version="3.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:storage="http://www.exammple.com/1"
  xmlns:office="http://www.exammple.com/2"
  xmlns:item="http://www.exammple.com/3"
  expand-text="yes">

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

  <xsl:mode on-no-match="shallow-skip"/>

  <!-- Parse JSON to XML -->

  <xsl:template match="data">
    <storage:one>
      <xsl:apply-templates select="json-to-xml(.)"/>
    </storage:one>
  </xsl:template>

  <!-- Print map -->
  <!-- <xsl:template match="*[@key = 'storage']"> <xsl:copy-of select=".."/> </xsl:template> -->

  <xsl:template match="*[@key='storage']">

      <xsl:for-each select="*[not(@key='milk')]">
      <xsl:element name="item:{@key}">
        <xsl:attribute name="office">plant-1</xsl:attribute>
        <xsl:value-of select="text()"/>
      </xsl:element>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="*[@key='milk']">
      <xsl:for-each select=".">
      <xsl:element name="item:{@key}">
        <xsl:attribute name="beverage">plant-2</xsl:attribute>
        <xsl:value-of select="text()"/>
      </xsl:element>
    </xsl:for-each>
  </xsl:template>

</xsl:transform>

结果:

<?xml version="1.0" encoding="UTF-8"?>
<storage:one xmlns:item="http://www.exammple.com/3"
             xmlns:office="http://www.exammple.com/2"
             xmlns:storage="http://www.exammple.com/1">
   <item:pencils office="plant-1">12</item:pencils>
   <item:rulers office="plant-1">4</item:rulers>
</storage:one>

想要的结果:

<?xml version="1.0" encoding="UTF-8"?>
<storage:one xmlns:item="http://www.exammple.com/3"
             xmlns:office="http://www.exammple.com/2"
             xmlns:storage="http://www.exammple.com/1">
   <item:pencils office="plant-1">12</item:pencils>
   <item:rulers office="plant-1">4</item:rulers>
   <item:milk beverage="plant-2">8</item:milk>
</storage:one>

解决方法

我会为每种不同的输出类型编写模板,如果输出顺序与 xsl:sort 或 XPath 3.1 sort 调用中的输入顺序不同,以更改顺序:

  <xsl:template match="data">
    <storage:one>
      <xsl:apply-templates select="json-to-xml(.)"/>
    </storage:one>
  </xsl:template>
  
  <xsl:template match="*[@key = 'storage']">
    <xsl:apply-templates select="sort(*,(),function($el) { $el/@key = 'milk' })"/>
  </xsl:template>

  <xsl:template match="*[@key='storage']/*[not(@key='milk')]">
      <xsl:element name="item:{@key}">
        <xsl:attribute name="office">plant-1</xsl:attribute>
        <xsl:value-of select="text()"/>
      </xsl:element>
  </xsl:template>

  <xsl:template match="*[@key='storage']/*[@key='milk']">
      <xsl:element name="item:{@key}">
        <xsl:attribute name="beverage">plant-2</xsl:attribute>
        <xsl:value-of select="text()"/>
      </xsl:element>
  </xsl:template>
,

您的第二个模板永远不会匹配,因为它永远不会到达。所有元素都由 <xsl:template match="*[@key='storage']"> 处理 - 它没有 <xsl:apply-templates ...> 以访问更多模板。

您的第一个模板不会递归到其子模板中。所以在第一个模板的末尾添加一个 <xsl:apply-templates select="*" />

    <xsl:template match="*[@key='storage']">
      <xsl:for-each select="*[not(@key='milk')]">
        <xsl:element name="item:{@key}">
          <xsl:attribute name="office">plant-1</xsl:attribute>
          <xsl:value-of select="text()"/>
        </xsl:element>
      </xsl:for-each>
      <xsl:apply-templates select="*" />
    </xsl:template>

这将尝试在“存储”级别应用更多模板,从而匹配第二个模板。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。