使所有元素的属性一致

时间:2013-04-22 06:24:58

标签: xml xslt

我有一个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实现吗?

4 个答案:

答案 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>