【问题标题】:Convert XML attributes to elements using XSLT使用 XSLT 将 XML 属性转换为元素
【发布时间】:2018-09-22 16:50:44
【问题描述】:

我正在尝试使用以下样式表将输入的 XML 文档属性转换为元素:

<?xml version="1.0"?>
      <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
      <xsl:output method="xml"/>
      <xsl:template match="*">
        <xsl:element name="{name()}">
          <xsl:for-each select="@*[name()!='type']">
            <xsl:element name="{name()}">
              <xsl:value-of select="."/>
            </xsl:element>
          </xsl:for-each>
          <xsl:apply-templates select="*|text()"/>
        </xsl:element>
      </xsl:template>
      </xsl:stylesheet>

然而,尽管基于每个元素属性正确地创建了新元素,“叶子”元素(即没有子元素)的文本与创建的元素混合在一起。例如

输入 XML

<order>
  <id>12345</id>
  <date>Today</date>
  <location country="PT">LX</location>
  <location country="ES">Barcelona</location>
  <items type="array" stock="true">
    <item>
      <id type="array">item1</id>
      <spec>
        <color type="array">brown</color>
        <price currency="euro">20</price>
        <usage>office</usage>
        <usage>home</usage>
      </spec>
    </item>
  </items>
</order>

输出 XML

<order>
  <id>12345</id>
  <date>Today</date>
  <location>
    <country>PT</country>LX
  </location>
  <location>
    <country>ES</country>Barcelona
  </location>
  <items>
    <stock>true</stock>
    <item>
      <id>item1</id>
      <spec>
        <color>brown</color>
        <price>
          <currency>euro</currency>20
        </price>
        <usage>office</usage>
        <usage>home</usage>
      </spec>
    </item>
  </items>
</order>

我想要什么

    ...
<location>
    <text>LX</text>
    <country>PT</country>
  </location>
  <location>
    <text>Barcelona</text>
    <country>ES</country>
  </location>
...
        <price>
          <text>20</text>
          <currency>euro</currency>
        </price>
       ...

我尝试了什么

<?xml version="1.0"?>
      <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
      <xsl:output method="xml"/>
      <xsl:template match="*">
        <xsl:element name="{name()}">
          <xsl:for-each select="@*[name()!='type']">
            <xsl:element name="text">
              <xsl:value-of select=".."/>
            </xsl:element>
            <xsl:element name="{name()}">
               <xsl:value-of select="."/>
             </xsl:element>
          </xsl:for-each>
          <xsl:apply-templates select="*|text()"/>
        </xsl:element>
      </xsl:template>
      </xsl:stylesheet>

问题 尽管正确地创建了新的元素标签

  <text>20</text>

它还在“非叶子”元素(即具有子元素的元素)上创建“文本”元素,获取提供的示例:

...
<items>
    <text>item1brown20officehome</text>
    <stock>true</stock>
    <item>
      <id>item1</id>
      <spec>
        <color>brown</color>
        <price>
          <text>20</text>
          <currency>euro</currency>20
        </price>
        <usage>office</usage>
        <usage>home</usage>
      </spec>
    </item>
  </items>
...

我不想

<text>item1brown20officehome</text>

有什么想法吗?提前致谢。

【问题讨论】:

  • 欢迎来到 Stack Overflow!很好的第一个问题。尤其是显示您尝试过的部分。 +1
  • 非常感谢@DanielHaley!不仅您的帮助对于解决这个问题至关重要,因为您在社区中提供了鼓励!

标签: xml xslt


【解决方案1】:

我不确定这是否会创建您想要的确切输出,因为您只包含了您想要的输出的一部分,但请尝试这样的操作...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="node()">
    <xsl:copy>
      <xsl:apply-templates select="text()"/>
      <xsl:apply-templates select="@*|*|comment()|processing-instruction()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*[@*]/text()">
    <text><xsl:value-of select="."/></text>
  </xsl:template>

  <xsl:template match="@*">
    <xsl:element name="{name()}">
      <xsl:value-of select="."/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

小提琴:http://xsltfiddle.liberty-development.net/jyH9rLX

如果我只想保留名称为“type”的属性怎么办? 属性(不将它们转换为元素,而是将它们保持原样 原来)。我怎样才能实现这样的目标?

更新的 XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="node()">
    <xsl:copy>
      <xsl:apply-templates select="@type|text()"/>
      <xsl:apply-templates 
        select="@*[not(name()='type')]|*|comment()|processing-instruction()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*[@*]/text()">
    <text><xsl:value-of select="."/></text>
  </xsl:template>

  <xsl:template match="@type">
    <xsl:copy-of select="."/>
  </xsl:template>

  <xsl:template match="@*">
    <xsl:element name="{name()}">
      <xsl:value-of select="."/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

更新小提琴:http://xsltfiddle.liberty-development.net/jyH9rLX/2

【讨论】:

  • 丹尼尔,再问一个问题。如果我只想保留名称为“type”的属性作为属性(不将它们转换为元素,而是保持它们原来的样子)怎么办。我怎样才能实现这样的目标?
  • @user9636427 - 在匹配@type的模板内添加&lt;xsl:copy-of select="."/&gt;
  • @user9636427 - 我忘了我们是在属性之前处理 text() ,所以还有一些工作要做。我们需要将type 属性与 text() 一起处理,然后在将模板应用到其他属性时忽略type 属性。这是它的样子:xsltfiddle.liberty-development.net/jyH9rLX/2 我也会更新我的答案。
  • 这将是我的以下问题!谢谢丹尼尔!同时,我还将这个模板&lt;xsl:template match="*[@*]/text()"&gt; 更新为&lt;xsl:template match="*[@*[not(name()='type')]]/text()"&gt;。这样,具有单个属性“type=array”的元素保持不变(即,没有添加新的 元素。我相信我之前没有完全提到这一点)。像魅力一样工作!
猜你喜欢
  • 2010-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-18
  • 1970-01-01
相关资源
最近更新 更多