【问题标题】:Unix XML file convert into Flat fileUnix XML文件转换为平面文件
【发布时间】:2011-05-27 02:36:30
【问题描述】:

我们在 unix 上有多个 xml 文件。我们需要将它们转换成平面文件。我们使用 C 对一级 xml 文件进行了解析(使用 C 是因为 C 可以与 Teradata fastload 通信,这是我们使用 inmod 的目标框,并且它将在一次解析中完成,否则在其他语言中我们需要进行两次解析一种用于转换为平面文件,一种用于加载 ito teradata)。即下面的文件

<book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>44.95</price>
   </book>

转换成

bk101~Gambardella, Matthew~XML Developer's Guide~Computer~44.95~

这是我们通过在 C 中解析文件来实现的。但是在看到下面的 xml 文件的原始格式之后。 (请不要将其视为必需文件。我只是提供一个想法)

<book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
             <modified>2010-01-02</modified>
             <modified>2010-01-03</modified>
      <price>44.95</price>
   </book>

这似乎应该转换为两条记录。

bk101~Gambardella, Matthew~XML Developer's Guide~Computer~2010-01-02~44.95~
bk101~Gambardella, Matthew~XML Developer's Guide~Computer~2010-01-03~44.95~

但是现在我们感觉我们的 C 代码对于这个 req 来说会很复杂。因此,我们正在寻找可以在 unix 上轻松使用的其他选项。任何人都可以给我们任何适用于 unix 的不同语言/选项的工作示例代码吗?

【问题讨论】:

    标签: c xml perl parsing unix


    【解决方案1】:

    您可以使用 XSLT。我使用可以在 Unix 上运行的 Saxon (Java)。

    此样式表处理您的两个 XML 示例:

    <?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"/>
      <xsl:template match="/book">
        <xsl:choose>
          <xsl:when test="modified">
            <xsl:for-each select="modified">
              <xsl:call-template name="dump-line">
                <xsl:with-param name="pos" select="position()"/>
              </xsl:call-template>          
            </xsl:for-each>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="@id"/><xsl:text>~</xsl:text>
            <xsl:value-of select="author"/><xsl:text>~</xsl:text>
            <xsl:value-of select="title"/><xsl:text>~</xsl:text>
            <xsl:value-of select="genre"/><xsl:text>~</xsl:text>
            <xsl:value-of select="price"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:template>
    
      <xsl:template name="dump-line">
        <xsl:param name="pos"/>
        <xsl:value-of select="/book/@id"/><xsl:text>~</xsl:text>
        <xsl:value-of select="/book/author"/><xsl:text>~</xsl:text>
        <xsl:value-of select="/book/title"/><xsl:text>~</xsl:text>
        <xsl:value-of select="/book/genre"/><xsl:text>~</xsl:text>
        <xsl:value-of select="/book/modified[$pos]"/><xsl:text>~</xsl:text>
        <xsl:value-of select="/book/price"/>
        <xsl:text>&#x0A;</xsl:text>
      </xsl:template>
    </xsl:stylesheet>
    

    如果没有modified 元素,则输出一条记录。如果有modified 元素,则输出与modified 元素一样多的记录。

    带有修改元素的示例输出:

    bk101~Gambardella, Matthew~XML Developer's Guide~Computer~2010-01-02~44.95
    bk101~Gambardella, Matthew~XML Developer's Guide~Computer~2010-01-03~44.95
    

    【讨论】:

    • 非常感谢。您提供了出色的工作示例。非常感谢。您的示例增加了我学习 XSLT 的兴趣。我使用 xalan(c 版本)来运行您的示例代码,并且运行良好。 Stackoverflow 极客很棒。感谢您的所有帮助和建议。我会尝试大多数可用的选项,并让你知道最终产品。
    • 再次非常感谢您。我能够为具有多个循环的更复杂的 xml 文件创建简单的 xslt 脚本。继续摇摆。因为你,我现在能够摆脱复杂化我的 600 行 C 代码并开始学习新语言的想法。现在我必须在我的组织使用 xalan 之后在我的 unix 上尝试相同的脚本和执行。
    • 不客气。我很高兴它有帮助。不过,您真的应该看看撒克逊人。 HE 版仍然是免费的,并且支持 XSLT 2.0。 saxon.sourceforge.net Xalan 不支持 2.0
    • 我正在尝试在我的 solaris 机器上安装 Xalan C。我从mirror.candidhosting.com/pub/apache//xml/xalan-c/binaries 链接获得了 Xalan-C_1_10_0-solaris_28_64-cc_62.tar.gz。在安装页面xml.apache.org/xalan-c/install.html 中,它说要将 xerces lib 添加到路径,但我在下载的 zip 中找不到它。你能帮忙吗?
    • 我也下载了 xerces 的 tar 文件并找到了那个 lib.但是我们是否需要它来使用 Xalan 来满足这个要求?
    【解决方案2】:

    如果您将数据加载到数据库中,并且您的字段与其他字段共享多对一关系,那么您需要确保您的数据库结构符合要求。 IE。书一表,修改日期一表。否则看起来好像有两本书,而实际上有一本书有两个修改日期。

    但是,如果您要将数据加载到数据库中,为什么要先将其转换为平面文件?你说你想避免两次解析一次。好吧,看起来您将通过一次解析 XML 并将其输出为平面文件,另一次解析平面文件并将其输入数据库。为什么不简单地解析 XML 并将数据直接放入数据库?

    发明像 XML 这样的格式是有原因的,其中之一是将复杂的数据关系封装在基于文本的文档中。通过转换为“平面文件”,您将失去这种复杂性。如果您打算将数据导入到可以处理这种复杂性并存储这些关系的环境中......为什么不保留它呢?

    您的数据库有 API,还是只能导入平面文件?

    ---编辑---

    作为答案的一部分进行回复比作为一系列 cmets 更容易。

    首先,感谢您的澄清。 其次,不,我不能提供示例代码。主要是因为你想要的听起来很具体。 第三,我认为你有两个选择:

    1) 您已经编写了大量用于解析 XML 的 C 代码。您必须考虑将其全部丢弃并在 Perl 中重新编写并支持它的成本,以及改进它以将数据直接导入 Teradata 数据库的成本以及之后维护它的成本。

    2) 对于 Perl,有许多 XML 解析器,根据我的经验,它们使遍历 XML 树/数据结构比在 C 中容易得多。我不是 Perl 的粉丝,但我已经编写了代码来处理在 C 中准备好解析的 XML 树,我从来没有讨厌过它。相比之下,在 Perl 中执行此操作更简单,甚至可能更快。

    有大量的 Perl 模块可以解析 XML。我建议您在互联网上搜索一些关于它们的评论,以决定哪个最容易或最适合您使用。

    有一个名为 Teradata::SQL 的 Perl 模块应该允许您将数据导入 Teradata 数据库。可能还有其他更容易/更简单/更好用的模块。我对其中任何一个都没有经验,因此无法提出建议。搜索 http://www.cpan.org 寻找任何可能有用的模块。


    最后,我强烈建议您花一些时间来确保您的 Teradata 数据库的设计与进入其中的数据相匹配。如上所述,您显然在修改日期和书籍之间存在多对一关系,因此这意味着您需要一个用于修改日期的表格和一个用于书籍的表格,并在您的表格设计中更正多对一关系。每行输入一个条目,导致同一本书的多行只有修改日期不同,这是非常错误的。可能还有其他多对一关系,例如作者。想象一下作者 A1 和 A2 写的书 B,修改日期为 M1 和 M2。如果您使用上面讨论过的方法,即每个组合有一行,那么您最终会为同一本书有 4 个条目,看起来您有 2 本书的标题相同但作者不同。

    花一些时间来确保您了解 XML 文件中数据的结构。这应该由 DTD 明确定义。

    【讨论】:

    • 对不起,有一个误解... Teradata inmod 工具是一个共享对象(Windows 中的 dll,unix 中的 dll),可以由 fastload 实用程序调用以获取要加载到 teradata 的记录。所以在这里我目前只对 xml 文件进行一次传递。 Teradata 对 xml 的支持较少,并且有一个粉碎选项,该选项只能在升级后支持,但近期不会。所以我们正在寻找其他选择,即使它们需要两次通过。您能否提供任何可以以这种方式转换的 perl/其他示例代码?感谢您的回复。
    • 非常感谢您的意见和建议。
    【解决方案3】:

    XSLT 是一个选项;查看xsltproc 工具。

    或者,您也可以使用更简单的 XQuery,尽管您可能需要强制它生成文本。以下 XQuery 脚本几乎可以满足您的需求(仅列出了几个字段):

    for $book in doc("book.xml")/book
    for $mod in $book/modified
    return concat($book/@id, "~", $book/title, "~", $mod, "
    ")
    

    您可以通过Saxon 使用

    java net.sf.saxon.Query '!method=text' script.xq
    

    另一个流行的 Unix XQuery 处理器是XQilla,虽然我不确定它是否能产生非 XML 输出。

    (对于生成换行符的笨拙方式,可能有一个聪明的替代方法。)

    【讨论】:

      【解决方案4】:

      如何将行格式化为bk101~Gambardella, Matthew~XML Developer's Guide~Computer~2010-01-02,2010-01-03~44.95~。当然,必须特别考虑修改的字段可以包含值列表的事实。这是你能做到的最平坦的地方。

      【讨论】:

      • 感谢您的回复。好吧,最终它应该被加载到数据库表中。所以这个记录应该分成两条记录进行报告。我们目前正在考虑 perl xml 解析器。任何人都知道 perl 上可以满足上述要求的任何示例代码吗?
      • 我敢打赌,如果你用谷歌搜索的话,会有很多例子。您必须使用脚本吗? Mono 作为一种工具可以接受吗? .NET 框架在解析和处理 XML 方面有很多优点,让它变得轻而易举......
      猜你喜欢
      • 2011-03-23
      • 2020-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-08
      相关资源
      最近更新 更多