我有一个XML文件,其中所有元素的属性都不一致
<Elem1 Attrib1="1" Attrib2="2"/>
<Elem2 Attrib1="21" Attrib3="23"/>
<Elem3 Attrib2="32" Attrib3="33" Attrib4="34"/>
我想要转换此文件,以便所有元素具有相同数量的属性,例如
<Elem1 Attrib1="1" Attrib2="2" Attrib3="" Attrib4=""/>
<Elem2 Attrib1="21" Attrib2="" Attrib3="23" Attrib4=""/>
<Elem3 Attrib1="" Attrib2="32" Attrib3="33" Attrib4="34"/>
这可以通过XSLT实现吗?
答案 0 :(得分:2)
这是一个XSLT 2.0选项。它可能被修改为适用于XSLT 1.0。
XML输入
<doc>
<Elem1 Attrib1="1" Attrib2="2"/>
<Elem2 Attrib1="21" Attrib3="23"/>
<Elem3 Attrib2="32" Attrib3="33" Attrib4="34"/>
</doc>
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="attrs" select="//@*/name()"/>
<xsl:key name="kAttrs" match="@*" use="name()"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[@*]">
<xsl:copy>
<xsl:for-each select="key('kAttrs',$attrs)">
<xsl:attribute name="{name(.)}"/>
</xsl:for-each>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<强>输出强>
<doc>
<Elem1 Attrib1="1" Attrib2="2" Attrib3="" Attrib4=""/>
<Elem2 Attrib1="21" Attrib2="" Attrib3="23" Attrib4=""/>
<Elem3 Attrib1="" Attrib2="32" Attrib3="33" Attrib4="34"/>
</doc>
这是另一个只有2.0的XSLT 2.0选项(这个选项 MUCH 更快):
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="attrs" select="distinct-values(//@*/name())"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[@*]">
<xsl:copy>
<xsl:for-each select="$attrs">
<xsl:attribute name="{.}"/>
</xsl:for-each>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
这将返回与上面相同的结果(带相同输入)。
答案 1 :(得分:1)
有很多可能的解决方案。 这里有一点点简单,假设你所关注的属性列表是众所周知的:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Elem1|Elem2|Elem3">
<xsl:copy >
<xsl:attribute name="Attrib1">
<xsl:value-of select="@Attrib1"/>
</xsl:attribute>
<xsl:attribute name="Attrib2">
<xsl:value-of select="@Attrib2"/>
</xsl:attribute>
<xsl:attribute name="Attrib3">
<xsl:value-of select="@Attrib3"/>
</xsl:attribute>
<xsl:attribute name="Attrib4">
<xsl:value-of select="@Attrib4"/>
</xsl:attribute>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<test>
<xsl:apply-templates />
</test>
</xsl:template>
</xsl:stylesheet>
答案 2 :(得分:0)
转型时
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Elem1|Elem2|Elem3">
<xsl:copy>
<xsl:if test="@Attrib1"><xsl:attribute name="Attrib1"><xsl:value-of select="@Attrib1"/></xsl:attribute></xsl:if>
<xsl:if test="not(@Attrib1)"><xsl:attribute name="Attrib1"></xsl:attribute></xsl:if>
<xsl:if test="@Attrib2"><xsl:attribute name="Attrib2"><xsl:value-of select="@Attrib2"/></xsl:attribute></xsl:if>
<xsl:if test="not(@Attrib2)"><xsl:attribute name="Attrib2"></xsl:attribute></xsl:if>
<xsl:if test="@Attrib3"><xsl:attribute name="Attrib3"><xsl:value-of select="@Attrib3"/></xsl:attribute></xsl:if>
<xsl:if test="not(@Attrib3)"><xsl:attribute name="Attrib3"></xsl:attribute></xsl:if>
<xsl:if test="@Attrib4"><xsl:attribute name="Attrib4"><xsl:value-of select="@Attrib4"/></xsl:attribute></xsl:if>
<xsl:if test="not(@Attrib4)"><xsl:attribute name="Attrib4"></xsl:attribute></xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
在XML 下面运行
<test>
<Elem1 Attrib1="1" Attrib2="2"/>
<Elem2 Attrib1="21" Attrib3="23"/>
<Elem3 Attrib2="32" Attrib3="33" Attrib4="34"/>
</test>
提供所需的输出
<?xml version='1.0' ?>
<test>
<Elem1 Attrib1="1" Attrib2="2" Attrib3="" Attrib4=""/>
<Elem2 Attrib1="21" Attrib2="" Attrib3="23" Attrib4=""/>
<Elem3 Attrib1="" Attrib2="32" Attrib3="33" Attrib4="34"/>
</test>
答案 3 :(得分:0)
这是XSLT 1.0中的通用方法。它包含一些额外的逻辑,以确保属性都以相同的顺序:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:key name="kAttr" match="@*" use="name()" />
<xsl:variable name="distinctAttr"
select="//@*[generate-id() =
generate-id(key('kAttr', name())[1])]" />
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*/*">
<xsl:copy>
<xsl:apply-templates select="$distinctAttr | @*">
<xsl:sort select="name()" />
<xsl:with-param name="parent" select="." />
</xsl:apply-templates>
<xsl:apply-templates select="node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="@*">
<xsl:param name="parent" select="/.." />
<xsl:if test="not($parent) or
count(.. | $parent) = 1 or
not($parent/@*[name() = name(current())])">
<xsl:attribute name="{name()}">
<xsl:value-of select="substring(., 1, string-length() *
(2 - count($parent | ..)))"/>
</xsl:attribute>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
在此输入上运行时:
<doc>
<Elem1 Attrib1="1" Attrib2="2"/>
<Elem2 Attrib1="21" Attrib3="23"/>
<Elem3 Attrib2="32" Attrib3="33" Attrib4="34"/>
</doc>
结果是:
<doc>
<Elem1 Attrib1="1" Attrib2="2" Attrib3="" Attrib4="" />
<Elem2 Attrib1="21" Attrib2="" Attrib3="23" Attrib4="" />
<Elem3 Attrib1="" Attrib2="32" Attrib3="33" Attrib4="34" />
</doc>