【问题标题】:How to convert complex Xml to csv?如何将复杂的 Xml 转换为 csv?
【发布时间】:2020-12-09 01:06:35
【问题描述】:

我正在用java(初级)编写一个程序,我真的需要xslt转换方面的帮助。有必要从 xml 制作一个 csv 文件。 我得到了这个 xslt 过滤器:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/>

    <xsl:template match="node()" name="conv">
        <xsl:call-template name="loop"/>
    </xsl:template>

    <xsl:template name="loop">

        <xsl:for-each select="./*[count(*) = 0]">
            <xsl:value-of select="."/>
            <xsl:if test="position() != last()">
                <xsl:text>,</xsl:text>
            </xsl:if>
            <xsl:if test="position() = last()">
                <xsl:text>,</xsl:text>
            </xsl:if>
        </xsl:for-each>
        <xsl:text>&#xA;</xsl:text>


        <xsl:for-each select="./*[(count(*) != 0) and (name()!='PARAMETRS')] ">
            <xsl:call-template name="loop"/>
        </xsl:for-each>
            <xsl:text>&#xA;</xsl:text>
    </xsl:template>
</xsl:stylesheet>

源xml:

<Integration>
    <PARAMETRS>
        <ID>AZD</ID>
        <DATE>2020-01-01</DATE>
    </PARAMETRS>
    <ORG>
        <Thing>
            <object>10220</object>
            <type>U</type>
            <dyn>
                <items>
                    <val>988009</val>
                    <datebegin>2019-12-12</datebegin>
                </items>
            </dyn>
        </Thing>
        <Thing>
            <object>10221</object>
            <type>U</type>
            <dyn>
                <items>
                    <val>988010</val>
                    <datebegin>2019-12-13</datebegin>
                </items>
                <items>
                    <val>988011</val>
                    <datebegin>2019-12-14</datebegin>
                </items>
            </dyn>
        </Thing>
    </ORG>
</Integration>

在输出中,我得到以逗号分隔的行,以及几行(相同的项目),其值如下。并且无法弄清楚如何连接这些值...... 我会通过 value-of select = "concat" 来做,但我可能有几个 dyn (1, 2, 3 ...),因此这不合适。 输出需要一个用逗号分隔的 csv。 请告知如何将项目与其父级连接起来?或者有更简单的方法来解析具有不同数量的子节(子)的 xml。

预期输出:

10220,U,988009,2019-12-12
10221,U,988010,2019-12-13,988011,2019-12-14

【问题讨论】:

  • 请在您的示例中显示预期的输出。 -- 提示:当输入不是作者设想的那样时,通用样式表通常不能按预期工作。
  • 预期输出:10220,U,988009,2019-12-12 和下一个 10221,U,988010,2019-12-13,988011,2019-12-14 以下的内容
  • 请不要在 cmets 中发布代码 - 改为编辑您的问题。确保我们可以清楚地看到输入中的哪些元素应该创建一个新行。

标签: java xml xslt


【解决方案1】:

如果您可以使用 XSLT 2.0,它将开辟新的强大功能。

Oracle XML 开发工具包 (XDK) 支持 XSLT 2.0

这里是链接:Using the XSLT Processor for Java

下面的方法是做以下事情:

  • 使用string-join() 函数连接所有子元素值 通过 .//*/(text()[1] 表达式在不同的层次结构级别上。
  • xs:token 转换会删除空格。
  • XPath 谓词[. != ''] 删除空序列成员。

XSLT 2.0

<?xml version='1.0'?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="text"/>

    <xsl:template match="/Integration">
        <xsl:for-each select="ORG/Thing">
            <xsl:value-of select="string-join((.//*/(text()[1] cast as xs:token?))[. != ''],',')"/>
            <xsl:text>&#xA;</xsl:text>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

输出

10220,U,988009,2019-12-12
10221,U,988010,2019-12-13,988011,2019-12-14

基于 Martining Honnen 的伟大提示,这里是更简洁的 XSLT 2.0 版本,没有任何循环。

XSLT 2.0

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="text"/>

    <xsl:template match="/Integration">
        <xsl:value-of select="ORG/Thing/string-join((.//*/(text()[1] cast as xs:token?))[. != ''],',')" separator="&#xA;"/>
    </xsl:template>
</xsl:stylesheet>

【讨论】:

  • 在 XSLT 2 中,甚至可以编写更紧凑的代码来使用 xsl:value-of separator 而不是嵌套的 xsl:for-each/xsl:value-of: &lt;xsl:value-of select="ORG/Thing/string-join((.//*/(text()[1] cast as xs:token?))[. != ''],',')" separator="&amp;#xA;"/&gt; 在 CSV 中创建行。
【解决方案2】:

您显示的输出可以使用以下样式表轻松获得:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:template match="/Integration">
    <xsl:for-each select="ORG/Thing">
        <xsl:value-of select="object"/>
        <xsl:text>,</xsl:text>
        <xsl:value-of select="type"/>
        <xsl:text>,</xsl:text>
        <xsl:for-each select="dyn/items">
            <xsl:value-of select="val"/>
            <xsl:text>,</xsl:text>
            <xsl:value-of select="datebegin"/>
            <xsl:if test="position() != last()">
                <xsl:text>,</xsl:text>
            </xsl:if>
        </xsl:for-each>
        <xsl:text>&#xA;</xsl:text>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

请注意,输出对于每个items 都有一组列;这不是一个理想的 CSV 结构。

【讨论】:

  • 太棒了!你保护我的时间!
猜你喜欢
  • 1970-01-01
  • 2019-12-11
  • 2014-08-07
  • 1970-01-01
  • 2020-06-10
  • 2021-10-29
  • 1970-01-01
  • 1970-01-01
  • 2013-11-14
相关资源
最近更新 更多