我有xml,结构如下
<root>
<PNode>
<node1>
<node1Child>data</node1Child>
<node2Child>data</node2Child>
</node1>
</PNode>
<SecondNode>
<node1>
<node1Child>
<child>data</child>
</node1Child>
</node1>
</SecondNode>
</root>
我想使用genric xslt输出,因为我有很多xml可以转换为这种格式。
<root>
<Pnode-node1-node1Child>data</Pnode-node1-node1Child>
<Pnode-node1-node2Child>data</Pnode-node1-node2Child>
<SecondNode-node1-node1child-child>data</SecondNode-node1-node1child-child>
</root>
可能更深或更少 我可以通过XSLT来做,请给出任何示例或参考
我想这样做是为了从sql server 2k8 r2 rdl生成PDF。因为rdl不接受嵌套的xml所以需要将其展平。
答案 0 :(得分:3)
此样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:param name="pName"/>
<xsl:apply-templates>
<xsl:with-param name="pName" select="concat($pName,name(),'-')"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="text()">
<xsl:param name="pName"/>
<xsl:element name="{substring($pName,1,string-length($pName)-1)}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
输出:
<root>
<PNode-node1-node1Child>data</PNode-node1-node1Child>
<PNode-node1-node2Child>data</PNode-node1-node2Child>
<SecondNode-node1-node1Child-child>data</SecondNode-node1-node1Child-child>
</root>
更新:如果可能有empy节点......
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:param name="pName"/>
<xsl:apply-templates>
<xsl:with-param name="pName" select="concat($pName,name(),'-')"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*[not(*)]">
<xsl:param name="pName"/>
<xsl:element name="{$pName}{name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
注意:匹配最内层元素。
答案 1 :(得分:3)
此转化:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="text()">
<xsl:variable name="vCompName">
<xsl:for-each select="ancestor::*[not(position() =last())]">
<xsl:value-of select="translate(name(), ':', '_')"/>
<xsl:if test="not(position()=last())">-</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:element name="{$vCompName}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档时:
<root>
<PNode>
<node1>
<node1Child>data</node1Child>
<node2Child>data</node2Child>
</node1>
</PNode>
<SecondNode>
<node1>
<node1Child>
<child>data</child>
</node1Child>
</node1>
</SecondNode>
</root>
会产生想要的正确结果:
<root>
<PNode-node1-node1Child>data</PNode-node1-node1Child>
<PNode-node1-node2Child>data</PNode-node1-node2Child>
<SecondNode-node1-node1Child-child>data</SecondNode-node1-node1Child-child>
</root>
<强>解释强>:
除了将文档包装在root
顶部元素中之外,只有一个模板。它匹配任何非空白文本节点。
除了文档顺序中的第一个元素祖先(反向轴ancestor::
中的最后一个)之外的所有元素祖先的节点集都使用'-'
字符和元素进行字符串连接用这个字符串作为名称构造。
在上面的2.中的字符串连接操作之前,每个名称都被修改,以便其中的任何':'
字符被下划线字符替换。如果某些名称中存在名称空间前缀,则这使得转换不会产生无效的复合名称。
最后,将当前文本节点复制为动态构造元素的子节点。
答案 2 :(得分:1)
鉴于此输入:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<PNode>
<node1>
<node1Child>data</node1Child>
<node2Child>data</node2Child>
</node1>
</PNode>
<SecondNode>
<node1>
<node1Child>
<child>data</child>
</node1Child>
</node1>
</SecondNode>
</root>
以下样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes" method="xml"/>
<xsl:template match="root">
<xsl:copy>
<xsl:apply-templates select="*" mode="flatten"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[normalize-space(text())]" mode="flatten">
<xsl:param name="name-prefix" select="''"/>
<xsl:variable name="name">
<xsl:call-template name="construct-name">
<xsl:with-param name="name-prefix" select="$name-prefix"/>
</xsl:call-template>
</xsl:variable>
<xsl:element name="{$name}">
<xsl:apply-templates select="text()"/>
</xsl:element>
<xsl:apply-templates select="node()" mode="flatten">
<xsl:with-param name="name-prefix" select="$name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*[not(normalize-space(text()))]" mode="flatten">
<xsl:param name="name-prefix" select="''"/>
<xsl:variable name="prefix">
<xsl:call-template name="construct-name">
<xsl:with-param name="name-prefix" select="$name-prefix"/>
</xsl:call-template>
</xsl:variable>
<xsl:apply-templates select="node()" mode="flatten">
<xsl:with-param name="name-prefix" select="$prefix"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template name="construct-name">
<xsl:param name="name-prefix"/>
<xsl:choose>
<xsl:when test="$name-prefix">
<xsl:value-of select="concat($name-prefix, '-', local-name(.))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="local-name(.)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="text()" mode="flatten"/>
</xsl:stylesheet>
产生想要的结果:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<PNode-node1-node1Child>data</PNode-node1-node1Child>
<PNode-node1-node2Child>data</PNode-node1-node2Child>
<SecondNode-node1-node1Child-child>data</SecondNode-node1-node1Child-child>
</root>
答案 3 :(得分:0)
在模板中,测试子节点。
如果有子节点,则将前一个参数值传递给该元素的名称。
如果只有#text,则使用参数作为名称输出新元素,并将其内容设置为#text