通过选择性保留将属性转换为值



我有以下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>

它导致以下内容,这部分是正确的,但它丢失了Entity元素上的 Type 属性:

<?xml version="1.0" encoding="UTF-8"?>
<Entity>
    <user-28/>
    <user-29>1</user-29>
    <has-change/>

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

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

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

执行保留大部分文档的转换时,最好使用标识转换模板。 这个呢:

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

你离得很近。请参阅下面我的答案中的细微变化。

当此 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>元素的效果)。
  • 最终模板与您已有的模板相同。

最新更新