具有以下xml输入
<?xml version="1.0" encoding="UTF-8"?>
<EnvelopeType1>
<Header>
<User>user1</User>
<Password>password</Password>
</Header>
<CustomerNumber>1</CustomerNumber>
<CustomerName>Me</CustomerName>
<Address>
<Number>5</Number>
<StreetName>High St</StreetName>
<State>MI</State>
</Address>
</EnvelopeType1>
通过xslt运行后我需要以下输出:
<EnvelopeType1 CustomerNumber="1" CustomerName="Me"/>
<Header User="user1" Password="password"/>
<Address Number="5" StreetName="High St" State="MI"/>
</EnvelopeType1>
根元素可能会更改为另一种类型,并且信封内的内容可能都会更改为不同的元素等,并且还会进入几个级别,所以我需要一些可以一般工作的东西。永远不会存在现有属性,它总是存在于元素中,因此转换后的元素不可能与现有属性具有相同的名称。
我认为这将使用apply-templates并以某种方式递归通过节点,但我对XSLT并不是那么有头脑,对此有所帮助。
这里有另一篇类似的帖子我觉得可行,但是需要XSLT2.0,我需要一些适用于XSLT1.0的东西
答案 0 :(得分:2)
既然你说你对XSLT不是很有兴趣,我会给你一个专注于概念问题的答案,而不是语法。 (如果您需要剪切/粘贴解决方案,则必须寻找其他答案。)
您需要一个适用于任何元素的模板。所以它的匹配模式可以是*
。
<xsl:template match="*">
...
</
在该模板中,您需要:
由于必须在第一个项目之前处理此列表中的第二个项目,因此您需要两个apply-templates指令,一个用于生成属性,另一个用于生成子项。对第一个使用不同的模式;可选地在每个apply-templates调用上使用select
属性,使调用仅适用于相应的子项;或者,为在特定模式下不产生输出的元素编写无操作模板。
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*[not(@*) and not(*)]"
mode="attribute-generation"/>
<xsl:apply-templates select="*[@* or *]"/>
</
</
为了使样式表更加通用,我们将保留输入中的属性,而不是假设没有任何属性。 (但为了简单起见,我们仍然假设属性和子项之间永远不会发生名称冲突;检查这对于XSLT学习者来说是一个很好的练习。)
<xsl:template match="@*"><xsl:copy/></xsl:template>
最后,编写一个模板来处理模式attribute-generation
中无属性,无子元素:
<xsl:template match="*" mode="attribute-generation">
<xsl:attribute name="{name()}">
<xsl:value-of select="."/>
</
</
答案 1 :(得分:0)
以下是您的问题的非常通用的解决方案。它只对输入XML的性质做出了最小的假设。 所做的假设只是具有子元素的元素应该包含所有元素作为属性。
除此之外,任何输入XML都可以。使用Saxon 6.5测试,在线试用here。用简单的英语做的是:
匹配至少包含一个子元素的元素。将此元素复制到 输出。对于它本身没有孩子的每个子元素 元素,添加以“无子”子项命名的属性 元素,并将其文本内容添加为属性值。
<强>样式表强>
编辑:作为对您评论的回复。现在,样式表为任意数量的“级别”提供了正确的输出。
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="*[*]">
<xsl:copy>
<xsl:for-each select="*[not(*)]">
<xsl:attribute name="{local-name(.)}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()"/>
</xsl:transform>
XML输出
<?xml version="1.0" encoding="UTF-8"?>
<EnvelopeType1 CustomerNumber="1" CustomerName="Me">
<Header User="user1" Password="password"/>
<Address Number="5" StreetName="High St" State="MI"/>
</EnvelopeType1>