我正在尝试创建一个XSL,该XSL使用以下步骤来转换XML:
如果看起来更容易,则该过程也可以按照指定步骤的相反顺序进行。
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文档中,则只会运行第一个模板。
答案 0 :(得分:1)
出于这个问题,我假设另一个模板看起来像这样
<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 Templates在key
元素上创建entry
属性。