xml - 具有多个模板的 XSL

标签 xml xslt

我正在尝试创建一个使用以下步骤转换 XML 的 XSL:

  1. 确定根“properties”下的元素是否具有以“foo”开头的名称。如果它不以“foo”开头,则删除该元素。
  2. 创建名为“entry”的新元素,其属性“key”等于以“foo”开头的元素的名称。

如果看起来更容易,该过程也可以按照指定步骤的相反顺序进行。

XML文档

<?xml version="1.0" encoding="UTF-8"?>
<properties>
    <oof>AAA</oof>
    <bar>BBB</bar>
    <foobar>CCC</foobar>
    <barfoo>DDD</barfoo>
    <foofoofoobar>EEE</foofoofoobar>
</properties>

我的 XSLT 仅将元素更改为条目

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">

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

  <xsl:template match="properties/*">
     <entry>
         <xsl:attribute name="key" select="name()"/>
         <xsl:apply-templates select="@* | node()"/>
     </entry>
  </xsl:template>

当我尝试使用另一个模板时<xsl:template match="properties[not(contains(name(), 'foo'))]"/> ,它不会在“entry”元素模板之后执行。如果我在条目模板之前执行模板,则不会执行条目模板。

所需输出

<?xml version="1.0" encoding="UTF-8"?>
<properties>
    <entry key="foobar">CCC</entry>
    <entry key="foofoofoobar">EEE</entry>
</properties>

非常感谢您的帮助。

编辑

我能够创建 <xsl:template match="entry[not(contains(@*, 'foo'))]"/>这将删除不包含 foo 的条目元素,这不完全是我想要的,但这是朝着正确方向迈出的又一步。但是,如果我将其全部放入一个 XSLT 文档中,则只有第一个模板会运行。

最佳答案

出于问题的目的,我假设另一个模板看起来像这样

<xsl:template match="properties[not(contains(name(), 'foo'))]" /> 

这与 properties 元素匹配,并且由于名称“properties”不包含文本“foo”,因此条件为 true,因此处理实际上在此停止(即 properties 不会被复制,并且所有子 entry 节点都不会匹配)。

您可能想这样做(我已从 contains 交换为 starts-with,因为这符合您的要求)

<xsl:template match="properties/*[not(starts-with(name(), 'foo'))]" /> 

但是...模板优先级存在问题。

元素 properties/bar (例如)将与您的两个模板相匹配,因此 XSLT 必须调用 Conflict Resolution for Template Rules (如果描述看起来太复杂,请查看http://www.lenzconsulting.com/how-xslt-works/#priority)。这意味着您的两个模板具有相同的优先级; 0.5。在这种情况下,通常会发生的情况是处理器将使用 XSLT 中最后一个匹配的模板,尽管某些处理器可能会发出错误信号。

要解决此问题,您可以给予模板优先级

<xsl:template match="properties/*[not(starts-with(name(), 'foo'))]" priority="0.6" />

或者您可以向其他模板添加条件

<xsl:template match="properties/*[starts-with(name(), 'foo')]">

或者您可以将两个模板合并为一个......

<xsl:template match="properties/*">
  <xsl:if test="starts-with(name(), 'foo')">
    <entry key="{name()}">
      <xsl:apply-templates select="@* | node()"/>
    </entry>
  </xsl:if>
</xsl:template>

尝试这个 XSLT(它使用优先级方法)

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">

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

  <xsl:template match="properties/*[not(starts-with(name(), 'foo'))]" priority="0.6" />

  <xsl:template match="properties/*">
     <entry key="{name()}">
         <xsl:apply-templates select="@* | node()"/>
     </entry>
  </xsl:template>
</xsl:stylesheet>

作为奖励,此 XSLT 还使用 Attribute Value Templatesentry 元素上创建 key 属性。

关于xml - 具有多个模板的 XSL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51858595/

相关文章:

html - IE随机打印出源代码(似乎不确定)

php - 解析并显示 xml 中的数据

xml - XSLT 转换以添加多个不存在的子元素

XSLT 在与根元素具有相同命名空间声明的内部标记中缺少命名空间

XSLT 模板模式 - xpath 评估

java - 将嵌套 XML 文件解析为节点集

xml - 在 Go 中使用交替内容类型解码 XML 元素

python - pypy:elementtree 标签名称只保留首字母?

xml - XSLT - 如何更改其值包含给定子字符串的任何属性的值

xml - 从 xml 元素数据中删除最后一个字符