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