我是XSLT样式表的新手,用于转换XML,我需要这个用于更大的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\TXT\2011\36\00000000\" 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\TXT\2011\36\00000000\" 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元素移动到与文档元素相同的文件中吗?
答案 0 :(得分:1)
简单地说:
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>
似乎我的BI(微软SSIS)XSLT转换不喜欢 strip-space macro:但它似乎与转换非常相关 因为没有它根本不起作用。有没有替代方案?
很难说出不合格的处理器会做什么或不做什么。尝试再添加一个模板:
<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)]"/>
答案 1 :(得分:0)
最后,我结合了原始设置和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>