将属性转换为具有选择性保留的值

时间:2012-11-16 08:01:26

标签: xml xslt

我有以下XML文档:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Entity Type="defect">
  <Fields>
    <Field Name="user-28"/>
    <Field Name="user-29">
      <Value>1</Value>
    </Field>
    <Field Name="has-change">
      <Value></Value>
    </Field>
    ...

我正在尝试对此进行转换,以便所有Field元素成为将Name属性转换为元素的元素,并且它会删除Fields元素。到目前为止,我使用以下转换取得了部分成功:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" encoding="UTF-8"
              indent="yes"/>
  <xsl:template match="//Entity">
    <xsl:copy>
      <xsl:apply-templates select="node()"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="Field">
    <xsl:element name="{@Name}">
      <xsl:value-of select="Value"/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

它会产生以下结果,部分正确,但它会丢失Type元素上的Entity属性:

<?xml version="1.0" encoding="UTF-8"?>
<Entity>

    <user-28/>
    <user-29>1</user-29>
    <has-change/>

另一个复杂因素是我需要这个来处理以下文档,其中包含一个Entities根节点,其中包含多个Entity个节点,而不会丢失根节点:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Entities TotalResults="60">
  <Entity Type="defect">
    <Fields>
      <Field Name="id">
        <Value>1161</Value>
      </Field>

2 个答案:

答案 0 :(得分:1)

<xsl:copy>仅复制节点本身,如果其属性或子节点则为none。应用于属性,它复制完整的属性,即名称和值。

在进行保留​​大部分文档的转换时,最好使用身份转换模板。那怎么样:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" encoding="UTF-8"
    indent="yes"/>

  <!-- Identity transform -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- We don't want to copy <Fields>, just the contents -->
  <xsl:template match="Fields">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="Field">
    <xsl:element name="{@Name}">
      <xsl:value-of select="Value"/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:1)

你非常接近。请看下面我的答案中的细微变化。

当这个XSLT 1.0解决方案:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output omit-xml-declaration="no" indent="yes"/>
  <xsl:strip-space elements="*"/>

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

  <xsl:template match="Fields">
     <xsl:apply-templates />
  </xsl:template>

  <xsl:template match="Field">
     <xsl:element name="{@Name}">
       <xsl:value-of select="Value" />
     </xsl:element>
  </xsl:template>

</xsl:stylesheet>

...适用于第一个提供的XML:

<?xml version="1.0" encoding="UTF-8"?>
<Entity Type="defect">
  <Fields>
    <Field Name="user-28"/>
    <Field Name="user-29">
      <Value>1</Value>
    </Field>
    <Field Name="has-change">
      <Value/>
    </Field>
    <!-- other <Field> elements -->
  </Fields>
</Entity>

...生成了想要的结果:

<?xml version="1.0"?>
<Entity Type="defect">
  <user-28 />
  <user-29>1</user-29>
  <has-change />
  <!-- other <Field> elements -->
</Entity>

如果针对第二个提供的XML运行相同的XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<Entities TotalResults="60">
  <Entity Type="defect">
    <Fields>
      <Field Name="id">
        <Value>1161</Value>
      </Field>
      <!-- other <Field> elements -->
    </Fields>
  </Entity>
</Entities>

...再次,产生了想要的结果:

<?xml version="1.0"?>
<Entities TotalResults="60">
  <Entity Type="defect">
    <id>1161</id>
    <!-- other <Field> elements -->
  </Entity>
</Entities>

<强>解释

  • 第一个模板是The Identity Transform。您可以猜测,其目的是默认情况下将所有节点和属性从源文档复制到结果文档中。
  • 第二个模板匹配所有<Fields>个元素。找到一个后,XSLT解析器被指示将模板应用于其子元素(此外,还具有删除<Fields>元素的效果)。
  • 最终模板与您已有的模板相同。