使用 XSLT 样式表对一个元素执行多项操作
Perform multiple operations on one element using XSLT stylesheet
我对用于转换 XML 的 XSLT 样式表还很陌生,我需要它来进行更大的 BI 项目。
我有以下 XML 结构:
<?xml version="1.0" encoding="UTF-16" standalone="no"?>
<zylab>
<document version="1.1" guid="{00A4A300-E76C-4373-A35B-1D2F0FF1336B}" date="20110908" time="08:48:52.436" size="2464" path="D:\ZYIMAGE DATA\INDEX DATA\EMD\TXT11[=10=]000000\" name="00000GFP.TXT" key="">
<fields>
<field id="Document_datum">20110830</field>
<field id="Document_type">value</field>
...
</fields>
</document>
</zylab>
我想使用 XSLT 将其转换为这种格式
<?xml version="1.0" encoding="UTF-8"?>
<zylab>
<document version="1.1" guid="{00A4A300-E76C-4373-A35B-1D2F0FF1336B}" date="20110908" time="08:48:52.436" size="2464" path="D:\ZYIMAGE DATA\INDEX DATA\EMD\TXT11[=11=]000000\" name="00000GFP.TXT" key="" />
<fields Document_datum="20110830" Document_type="value" ... />
</zylab>
到目前为止,我已经能够使用以下 XSLT 完成其中的一部分:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!--Identity template, provides default behavior that copies all content into the output -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- copy node one level up -->
<xsl:template match="fields">
<xsl:copy>
<xsl:apply-templates select="child::node()[not(self::field)]"/>
</xsl:copy>
<xsl:apply-templates select="field"/>
</xsl:template>
<!-- transpose elements to attributes -->
<xsl:template match="fields">
<xsl:element name="fields">
<xsl:for-each select="*">
<xsl:attribute name="{@id}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
问题是片段确实独立工作,但我无法让它对同一元素执行这两个操作。
输出取决于我的片段的顺序,后者总是适用的。如果我注释掉其中一个,另一个似乎可以正常工作。
这里有人知道如何修改我的 XSLT 以对 fields 元素执行这两个操作,以便将它的 fields 子元素合并到属性并将 fields 元素移动到与文档元素相同的级别吗?
简单的怎么样:
XSLT 1.0
<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:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- convert each field to an attribute of parent element (fields) -->
<xsl:template match="field">
<xsl:attribute name="{@id}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
请注意,这里假定 id
属性的内容适合构成有效的属性名称。
编辑:
如果要将 fields
元素移动为 document
的同级元素,请再添加一个模板:
<!-- move fields to be a sibling of document -->
<xsl:template match="document">
<xsl:copy>
<xsl:apply-templates select="@*"/>
</xsl:copy>
<xsl:apply-templates select="fields"/>
</xsl:template>
编辑 2:
it seems my BI (Microsoft SSIS) XSLT transformation does not like the
strip-space macro: But it seems pretty relevant to the transformation
as w/o it it does not work at all. Is there any alternative solution?
很难说不合格的处理器会做什么或不会做什么。尝试再添加一个模板:
<xsl:template match="fields">
<xsl:copy>
<xsl:apply-templates select="field"/>
</xsl:copy>
</xsl:template>
或替换此模板:
<!-- convert each field to an attribute of parent element (fields) -->
<xsl:template match="field">
<xsl:attribute name="{@id}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
与:
<xsl:template match="fields">
<xsl:copy>
<xsl:for-each select="field">
<xsl:attribute name="{@id}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:for-each>
</xsl:copy>
</xsl:template>
或者使用以下方法删除仅包含空白的文本节点:
<xsl:template match="text()[not(string)]"/>
最终我结合了我的原始设置和 michael.hor257k 的答案,这是在我的 BI 解决方案 (SSIS) 的外部和内部工作的 XSLT 样式表:
<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>
<!-- transpose elements to attributes -->
<xsl:template match="fields">
<xsl:element name="fields">
<xsl:for-each select="*">
<xsl:attribute name="{@id}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:for-each>
</xsl:element>
</xsl:template>
<!-- move fields to be a sibling of document -->
<xsl:template match="document">
<xsl:copy>
<xsl:apply-templates select="@*"/>
</xsl:copy>
<xsl:apply-templates select="fields"/>
</xsl:template>
</xsl:stylesheet>
我对用于转换 XML 的 XSLT 样式表还很陌生,我需要它来进行更大的 BI 项目。
我有以下 XML 结构:
<?xml version="1.0" encoding="UTF-16" standalone="no"?>
<zylab>
<document version="1.1" guid="{00A4A300-E76C-4373-A35B-1D2F0FF1336B}" date="20110908" time="08:48:52.436" size="2464" path="D:\ZYIMAGE DATA\INDEX DATA\EMD\TXT11[=10=]000000\" name="00000GFP.TXT" key="">
<fields>
<field id="Document_datum">20110830</field>
<field id="Document_type">value</field>
...
</fields>
</document>
</zylab>
我想使用 XSLT 将其转换为这种格式
<?xml version="1.0" encoding="UTF-8"?>
<zylab>
<document version="1.1" guid="{00A4A300-E76C-4373-A35B-1D2F0FF1336B}" date="20110908" time="08:48:52.436" size="2464" path="D:\ZYIMAGE DATA\INDEX DATA\EMD\TXT11[=11=]000000\" name="00000GFP.TXT" key="" />
<fields Document_datum="20110830" Document_type="value" ... />
</zylab>
到目前为止,我已经能够使用以下 XSLT 完成其中的一部分:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!--Identity template, provides default behavior that copies all content into the output -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- copy node one level up -->
<xsl:template match="fields">
<xsl:copy>
<xsl:apply-templates select="child::node()[not(self::field)]"/>
</xsl:copy>
<xsl:apply-templates select="field"/>
</xsl:template>
<!-- transpose elements to attributes -->
<xsl:template match="fields">
<xsl:element name="fields">
<xsl:for-each select="*">
<xsl:attribute name="{@id}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
问题是片段确实独立工作,但我无法让它对同一元素执行这两个操作。 输出取决于我的片段的顺序,后者总是适用的。如果我注释掉其中一个,另一个似乎可以正常工作。
这里有人知道如何修改我的 XSLT 以对 fields 元素执行这两个操作,以便将它的 fields 子元素合并到属性并将 fields 元素移动到与文档元素相同的级别吗?
简单的怎么样:
XSLT 1.0
<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:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- convert each field to an attribute of parent element (fields) -->
<xsl:template match="field">
<xsl:attribute name="{@id}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
请注意,这里假定 id
属性的内容适合构成有效的属性名称。
编辑:
如果要将 fields
元素移动为 document
的同级元素,请再添加一个模板:
<!-- move fields to be a sibling of document -->
<xsl:template match="document">
<xsl:copy>
<xsl:apply-templates select="@*"/>
</xsl:copy>
<xsl:apply-templates select="fields"/>
</xsl:template>
编辑 2:
it seems my BI (Microsoft SSIS) XSLT transformation does not like the strip-space macro: But it seems pretty relevant to the transformation as w/o it it does not work at all. Is there any alternative solution?
很难说不合格的处理器会做什么或不会做什么。尝试再添加一个模板:
<xsl:template match="fields">
<xsl:copy>
<xsl:apply-templates select="field"/>
</xsl:copy>
</xsl:template>
或替换此模板:
<!-- convert each field to an attribute of parent element (fields) -->
<xsl:template match="field">
<xsl:attribute name="{@id}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
与:
<xsl:template match="fields">
<xsl:copy>
<xsl:for-each select="field">
<xsl:attribute name="{@id}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:for-each>
</xsl:copy>
</xsl:template>
或者使用以下方法删除仅包含空白的文本节点:
<xsl:template match="text()[not(string)]"/>
最终我结合了我的原始设置和 michael.hor257k 的答案,这是在我的 BI 解决方案 (SSIS) 的外部和内部工作的 XSLT 样式表:
<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>
<!-- transpose elements to attributes -->
<xsl:template match="fields">
<xsl:element name="fields">
<xsl:for-each select="*">
<xsl:attribute name="{@id}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:for-each>
</xsl:element>
</xsl:template>
<!-- move fields to be a sibling of document -->
<xsl:template match="document">
<xsl:copy>
<xsl:apply-templates select="@*"/>
</xsl:copy>
<xsl:apply-templates select="fields"/>
</xsl:template>
</xsl:stylesheet>