1

我有一个 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

4 回答 4

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>

这是另一个 XSLT 2.0 选项,它只是 2.0(这个也快得多):

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

这将返回与上面相同的结果(带有相同的输入)。

于 2013-04-22T07:15:36.567 回答
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>
于 2013-04-22T07:07:35.967 回答
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>
于 2013-04-22T06:51:46.900 回答
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>
于 2013-04-22T08:36:31.477 回答