我是XSLT的新手,现在我有一个相当复杂的问题...我的输入文件看起来像
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<doc>
<outerElement>
<first>
<textElement>Some Text</textElement>
</first>
<second>
<textElement>Some Text</textElement>
</second>
<third>
<textElement>Some Text</textElement>
</third>
</outerElement>
</doc>
“第二个”元素出现问题。在输入文件中,它可以有以下三种形式之一:
MISSING
<second>
<textElement>Some Text</textElement>
</second>
<second missingCause="" />
在输出文件中,它应该像第二种形式一样插入。如果它在textElement指示它被模板插入之前丢失了,那么重要的是它必须位于第二个位置,因为我想根据xsd模式验证它...
这是我目前的XSL:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- COPY ALL ELEMENTS -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- remove Elements with attribute deleteme -->
<xsl:template match="outerElement/second[@missingCause='*']" />
<!-- look if second is there. If not insert -->
<xsl:template match="outerElement">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<xsl:if test="not(second)">
<second>
</second>
</xsl:if>
</xsl:copy>
</xsl:template>
<!-- Insert Element second -->
<xsl:template match="outerElement/second">
<xsl:apply-templates select="node()|@*"/>
<xsl:copy>
<xsl:if test="not(textElement)">
<textElement>Inserted by Template</textElement>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
如果缺少“秒”,我的输出文件只会得到一个元素“”,但它是空的,最后一个转换不会被应用。其他一切看起来很好,而当我在文件中我收到警告......
是否有人可以帮我将元素移动到原来的位置,以便对Schema进行验证并使其在所有三种情况下都能正常工作?
我认为我的方式似乎不太好并且最终会变得混乱,因为我有几个类似的元素插入/删除像这样。
感谢阅读;)
答案 0 :(得分:4)
这是一个通用的解决方案,适用于outerElement
的任意数量的不同命名的子项以及它们之间的任何首选顺序:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pUncertainElName" select="'second'"/>
<xsl:param name="pOrderedNames" select="'|first|second|third|'"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="outerElement">
<xsl:variable name="vrtfFirstPass">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<xsl:apply-templates select=
"self::*[not(*[name() = $pUncertainElName])
or
*[name()=$pUncertainElName and @missing-cause]]"
mode="missing"/>
</xsl:copy>
</xsl:variable>
<xsl:apply-templates select="ext:node-set($vrtfFirstPass)/*" mode="pass2"/>
</xsl:template>
<xsl:template match="*[@missing-cause]"/>
<xsl:template match="*" mode="missing">
<xsl:element name="{$pUncertainElName}">
<textElement>Some Text</textElement>
</xsl:element>
</xsl:template>
<xsl:template match="outerElement" mode="pass2">
<xsl:copy>
<xsl:apply-templates>
<xsl:sort data-type="number" select=
"string-length(substring-before($pOrderedNames,
concat('|', name(), '|')
)
)"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
对以下XML文档应用此转换时:
<doc>
<outerElement>
<first>
<textElement>Some Text</textElement>
</first>
<second missing-cause="">
<textElement>Some Text</textElement>
</second>
<third>
<textElement>Some Text</textElement>
</third>
</outerElement>
</doc>
产生了想要的正确结果:
<doc>
<outerElement>
<first>
<textElement>Some Text</textElement>
</first>
<second>
<textElement>Some Text</textElement>
</second>
<third>
<textElement>Some Text</textElement>
</third>
</outerElement>
</doc>
在此XML文档上应用时:
<doc>
<outerElement>
<first>
<textElement>Some Text</textElement>
</first>
<third>
<textElement>Some Text</textElement>
</third>
</outerElement>
</doc>
再次生成想要的正确结果:
<doc>
<outerElement>
<first>
<textElement>Some Text</textElement>
</first>
<second>
<textElement>Some Text</textElement>
</second>
<third>
<textElement>Some Text</textElement>
</third>
</outerElement>
</doc>
最后,当对此XML文档应用相同的转换时:
<doc>
<outerElement>
<first>
<textElement>Some Text</textElement>
</first>
<second>
<textElement>Some Text</textElement>
</second>
<third>
<textElement>Some Text</textElement>
</third>
</outerElement>
</doc>
同样想要的,产生了正确的结果:
<doc>
<outerElement>
<first>
<textElement>Some Text</textElement>
</first>
<second>
<textElement>Some Text</textElement>
</second>
<third>
<textElement>Some Text</textElement>
</third>
</outerElement>
</doc>
请注意:
outerElement
(不仅仅是三个)可以有任意数量的不同名称的孩子,而且他们的订单可能不会提前知道。
例如:
鉴于此XML文档:
<doc>
<outerElement>
<first>
<textElement>Some Text</textElement>
</first>
<second missing-cause="">
<textElement>Some Text</textElement>
</second>
<third>
<textElement>Some Text</textElement>
</third>
<fourth>
<textElement>Some Text</textElement>
</fourth>
</outerElement>
</doc>
和此订单:第四,第二,第三,第一
我们只需要替换:
<xsl:param name="pOrderedNames" select="'|first|second|third|'"/>
<强>与强>:
<xsl:param name="pOrderedNames" select="'|fourth|second|third|first|'"/>
现在生成新的通缉结果:
<doc>
<outerElement>
<fourth>
<textElement>Some Text</textElement>
</fourth>
<second>
<textElement>Some Text</textElement>
</second>
<third>
<textElement>Some Text</textElement>
</third>
<first>
<textElement>Some Text</textElement>
</first>
</outerElement>
</doc>
<强>解释强>:
这是两次转换。
在外部/全局参数$pUncertainElName
中指定可能存在或可能不存在的元素的名称。为方便起见,我们将此元素称为second
。
在第一次传递中,outerElement
的{{1}}除second
属性之外的所有子项都按“原样”复制。如果missing-cause
元素不存在或具有second
属性,我们会输出一个新的missing-cause
子元素 - 完全想要的outerElement
元素。
在第二遍中,我们根据其优先级对第一遍中生成的second
的子项进行排序,如另一个名为outerElement
的外部/全局参数(名称)中所指定的在此字符串中留下另一个名称,具有更高的优先级)
答案 1 :(得分:3)
我认为你误解了模板的工作原理。对于您需要完成的任务,似乎只需要一个模板(加上身份模板)。尝试并反馈:
<xsl:template match="outerElement[not(second) or second[@missingCause='']]">
<xsl:apply-templates select="@*|first"/>
<second>
<textElement>Inserted by Template</textElement>
</second>
<xsl:apply-templates select="third"/>
</xsl:template>