Sql server 使用XSLT将层次xml转换为平面xml

Sql server 使用XSLT将层次xml转换为平面xml,sql-server,sql-server-2008,xslt,reporting-services,Sql Server,Sql Server 2008,Xslt,Reporting Services,我有如下结构的xml <root> <PNode> <node1> <node1Child>data</node1Child> <node2Child>data</node2Child> </node1> </PNode> <SecondNode> <node1> <node1Child&

我有如下结构的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吗?请给出一些例子或参考资料


我想从SQLServer2K8R2 rdl生成PDF。因为rdl不接受嵌套的xml,所以需要将其展平。

在模板中,测试子节点

如果存在子节点,则将上一个参数值传递给它,该参数值与此元素的名称连接在一起

如果只有#text,则使用参数作为其名称输出新元素,并将其内容设置为#text

,给定此输入:

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

产生想要的结果:

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

数据
数据
数据
此样式表:

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


注意:匹配最里面的元素。

此转换

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

数据
数据
数据
说明

<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>
  • 除了用
    根元素
    顶元素包装文档外,只有一个模板。它匹配任何非纯空白文本节点

  • 除了文档顺序中的第一个元素祖先(即反向轴
    祖先::
    中的最后一个)之外,所有元素祖先的节点集都是用
    '-'
    字符连接的字符串,并且元素是以该字符串作为名称构造的

  • 在2中的字符串联接操作之前。在上面,每个名称都被修改,以便其中的任何
    :'
    字符都被下划线字符替换。这样,如果某些名称中有名称空间前缀,则转换不会产生无效的复合名称

  • 最后,将当前文本节点复制为动态构造元素的子元素


  • 假设你的意思是好问题,+1。请参阅我的答案,以获得完整、简短且简单的解决方案。还提供了广泛的解释。转换是健壮的,在名称空间和前缀名称的情况下可以工作。@Alex Nikolaenkov这不是给我节点。输出datadatadata@Jagan,如果使用浏览器查看结果,请使用
    查看源代码
    检查xml文档。我已经用XalanXSLT处理器验证了我的样式表。嘿,alex,它不起作用了,我试过使用XMLSpy、StylusStuio和c#代码。只提供数据的节点根本不会出现。我刚得到数据。请重新检查。@Techmaster,请指定您的
    XSLT处理器
    。我正在使用C#中的代码进行处理。我还尝试使用XML间谍工具。所有人都只提供数据。Thx.+1是一个好答案。顺便说一句,如果test
    expr用一个额外的括号括起来,为什么你的
    ?@Flack:谢谢。至于额外的括号:我开始用C#
    if
    语句编写它,然后注意到我在做什么,并将它放在
    test
    属性:)中。“这会简化它。”亚历杭德罗回答得很小,很完美。非常感谢。@Alejandro,您好,match=“text()”忽略空标记,我也需要包含它。e、 g如果SecondNode-node1-node1child-child为空,则此xlst将不包括在最终xml中。任何调整。