【问题标题】:XML output from MySQL queryMySQL 查询的 XML 输出
【发布时间】:2010-05-17 08:46:34
【问题描述】:

是否有机会将 MySQL 查询的输出直接转换为 XML?

我指的是类似于 MSSQL 的 SQL-XML 插件,例如:

SELECT * FROM table WHERE 1 FOR XML AUTO

返回包含生成的 XML 标记结构的文本(准确地说是 MSSQL 中的 xml 数据类型) 根据表中的列。

使用 SQL-XML 还可以选择显式定义输出 XML 结构,如下所示:

SELECT
  1       AS tag,
  NULL    AS parent,
  emp_id  AS [employee!1!emp_id],
  cust_id    AS [customer!2!cust_id],
  region    AS [customer!2!region]
 FROM table
 FOR XML EXPLICIT

生成如下 XML 代码:

<employee emp_id='129'>
   <customer cust_id='107' region='Eastern'/>
</employee>

你有什么线索可以在 MySQL 中实现吗?

提前感谢您的回答。

【问题讨论】:

    标签: mysql xml database sqlxml


    【解决方案1】:

    mysql 命令可以使用--xml 选项直接输出 XML,该选项至少可追溯到 MySql 4.1。

    但是,这不允许您自定义 XML 输出的结构。它会输出如下内容:

    <?xml version="1.0"?>
    <resultset statement="SELECT * FROM orders" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <row>
        <field name="emp_id">129</field>
        <field name="cust_id">107</field>
        <field name="region">Eastern</field>
      </row>
    </resultset>
    

    而你想要:

    <?xml version="1.0"?>
    <orders>
      <employee emp_id="129">
        <customer cust_id="107" region="Eastern"/>
      </employee>
    </orders>
    

    转换可以通过XSLT 使用如下脚本来完成:

    <?xml version="1.0"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    
      <xsl:output indent="yes"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:template match="resultset">
        <orders>
          <xsl:apply-templates/>
        </orders>
      </xsl:template>
    
      <xsl:template match="row">
        <employee emp_id="{field[@name='emp_id']}">
          <customer
            cust_id="{field[@name='cust_id']}"
            region="{field[@name='region']}"/>
        </employee>
      </xsl:template>
    
    </xsl:stylesheet>
    

    这显然比简洁的 MSSQL 语法更冗长,但另一方面,它功能更强大,可以完成 MSSQL 中不可能完成的各种事情。

    如果您使用诸如xsltprocsaxon 之类的命令行XSLT 处理器,您可以将mysql 的输出直接通过管道传送到XSLT 程序中。例如:

    mysql -e 'select * from table' -X database | xsltproc script.xsl -
    

    【讨论】:

    • 这只给出了一个带有通用元素名称的平面结果,它与 MSSQL 的 FOR XML 并没有真正可比性。
    • @Emyr,你是对的。 OP 要求与 MSSQL 的功能等效。我会用 XSLT 来做。我会为此更新我的答案。
    【解决方案2】:

    Using XML with MySQL 似乎是从 MySQL 查询到 XML 的各种不同方法开始的好地方。

    来自文章:

       use strict;
       use DBI;
       use XML::Generator::DBI;
       use XML::Handler::YAWriter;
    
       my $dbh = DBI->connect ("DBI:mysql:test",
                               "testuser", "testpass",
                               { RaiseError => 1, PrintError => 0});
       my $out = XML::Handler::YAWriter->new (AsFile => "-");
       my $gen = XML::Generator::DBI->new (
                                       Handler => $out,
                                       dbh => $dbh
                                   );
       $gen->execute ("SELECT name, category FROM animal");
       $dbh->disconnect ();
    

    【讨论】:

    • 不是来自 MySQL 的 XML,因为需要 Perl 解释器……不过我喜欢它! => +1
    • 嗨,我想要一个来自 MySQL 的 XML,没有任何解释器。有什么解决办法吗?
    【解决方案3】:

    您知道如何在 MySQL 中实现这一点吗?

    是的,步行并使用CONCAT 字符串自己制作xml。试试

    SELECT concat('&lt;orders&gt;&lt;employee emp_id="', emp_id, '"&gt;&lt;customer cust_id="', cust_id, '" region="', region, '"/&gt;&lt;/employee&gt;&lt;/orders&gt;') FROM table

    我从 2009 年的回答 How to convert a MySQL DB to XML? 中得到这个,它似乎仍然有效。不是很方便,如果每个项目都有大树,它们都将在根项目的一个连接值中,但它有效,请参见这个带有假人的测试:

    SELECT concat('&lt;orders&gt;&lt;employee emp_id="', 1, '"&gt;&lt;customer cust_id="', 2, '" region="', 3, '"/&gt;&lt;/employee&gt;&lt;/orders&gt;') FROM DUAL

    给予

    &lt;orders&gt;&lt;employee emp_id="1"&gt;&lt;customer cust_id="2" region="3"/&gt;&lt;/employee&gt;&lt;/orders&gt;

    通过“手动编码”,你可以得到这个结构。

    <?xml version="1.0"?>
    <orders>
      <employee emp_id="1">
        <customer cust_id="2" region="3" />
      </employee>
    </orders>
    

    我用每个根项目的更大树检查了这个,它工作了,但是我必须在它上面运行一个额外的 Python 代码来摆脱当你在 xml 路径中有中等级别节点时生成的太多的打开和关闭。可以将回溯列表与临时集合中的条目一起使用,我已经完成了,但是面向对象的方式会更专业。我刚刚编写了代码,以便在找到新的头项后立即从列表中删除最后的 x 项,以及嵌套分支的一些其他技巧。工作。

    我想出了一个找到标签之间每个文本的正则表达式:

    string = "     <some tag><another tag>test string<another tag></some tag>"
    pattern = r'(?:^\s*)?(?:(?:<[^\/]*?)>)?(.*?)?(?:(?:<\/[^>]*)>)?'
    p = re.compile(pattern)
    val = r''.join(p.findall(string))
    val_escaped = escape(val)
    if val_escaped != val:
        string.replace(val, val_escaped)
    

    此正则表达式可帮助您访问标签之间的文本。如果您被允许使用 CDATA,那么在任何地方使用它是最简单的。只需在 MySQL 中制作内容“CDATA”(字符数据)即可:

    <Title><![CDATA[', t.title, ']]></Title>
    

    除了非常奇怪的字符(如 (U+001A))之外,您将不会再遇到任何问题,您应该在 MySQL 中替换它们。然后,您根本不需要关心转义和替换其余的特殊字符。在 1 Mio 上为我工作。行 xml 文件,大量使用特殊字符。

    然而:您应该使用 Python 的模块 xmlschema 对照所需的 xml 模式文件来验证文件。当您不允许使用该 CDATA 技巧时,它会提醒您。

    如果您需要不带 CDATA 的完全 UTF-8 格式的内容(这通常是一项任务),您甚至可以通过针对 xml 逐步验证代码输出(= xml 输出)在 1 Mio 行文件中实现该目标架构文件(目标是 xsd)。这是一项繁琐的工作,但可以通过一些耐心来完成。 可以替换为:

    • MySQL 使用 replace()
    • Python 使用 string.replace()
    • Python 使用 Regex 替换(虽然我最终不需要它,它看起来像:re.sub(re.escape(val), 'xyz', i)
    • string.encode(encoding = 'UTF-8', errors = 'strict')

    请注意,编码为 utf-8 是最强大的一步,它甚至可以抛开上述所有其他三种替换方式。还要注意:它使文本成为二进制,然后您需要将其视为二进制 b'...',因此您可以使用 wb 仅以二进制模式将其写入文件。

    最后,您可以在普通浏览器(如 Firefox)中打开 XML 输出以进行最终检查并观察 XML 的工作情况。或者使用 xml 扩展在 vscode/codium 中检查它。但是不需要这些检查,在我的例子中,xmlschema 模块已经很好地显示了一切。还要注意,vscode/codium 可以很容易地处理 xml 问题,并且当 Firefox 不能时仍然显示树,因此,您需要一个验证器或浏览器来查看所有 xml 错误。

    使用这个 xml-building-with-mysql 可以完成一个相当大的项目,最后有一个三重嵌套的 xml 树,父节点中有许多重复的标签,所有这些都是由二维 MySQL 输出制成的。

    【讨论】:

      猜你喜欢
      • 2012-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-20
      • 1970-01-01
      • 2020-08-25
      相关资源
      最近更新 更多