将没有子元素的所有XML元素转换为父元素的XML属性

时间:2014-08-22 13:22:49

标签: xml xslt-1.0

具有以下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的东西

2 个答案:

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