将XML文件同步到MySQL数据库

时间:2014-06-06 11:15:04

标签: mysql sql xml synchronization database-schema

我公司使用内部管理软件存储产品。他们希望将所有产品转置到MySql数据库中,以便他们可以在公司网站上提供他们的产品。

注意:他们将继续使用自己的内部软件。该软件可以以各种文件格式(包括XML)导出所有产品。

同步化不一定是实时的,他们满意每天(深夜)同步MySql数据库。

此外,他们软件中的每个产品都有一个或多个图像,然后我还要提供网站上的图像。

以下是XML导出的示例:

<?xml version="1.0" encoding="UTF-8"?>
<export_management userid="78643">
    <product id="1234">
        <version>100</version>
        <insert_date>2013-12-12 00:00:00</insert_date>
        <warrenty>true</warrenty>
        <price>139,00</price>
        <model>
            <code>324234345</code>
            <model>Notredame</model>
            <color>red</color>
            <size>XL</size>
        </model>
        <internal>
            <color>green</color>
            <size>S</size>
        </internal>
        <options>
            <s_option>aaa</s_option>
            <s_option>bbb</s_option>
            <s_option>ccc</s_option>
            <s_option>ddd</s_option>
            <s_option>eee</s_option>
            <s_option>fff</s_option>
      ...
            <extra_option>ggg</extra_option>
            <extra_option>hhh</extra_option>
            <extra_option>jjj</extra_option>
            <extra_option>kkk</extra_option>
      ...
        </options>
        <images>
            <image>
                <small>1234_0.jpg</small>
            </image>
            <image>
                <small>1234_1.jpg</small>
            </image>
        </images>
    </product>
    <product id="5321">
    ...
    </product>
    <product id="2621">
    ...
    </product>
  ...
</export_management>

有关如何做的一些想法?

如果我的问题不明确,请告诉我。感谢


修改 我为每个表使用了这样的SQL来填充XML数据:

LOAD XML LOCAL INFILE '/products.xml' INTO TABLE table_name ROWS IDENTIFIED BY '<tag_name>';

然后,检查表格内容我可以看到字段“id”(主键)自动为每个表中的每个相应产品行保持相同。这是正确的,令人惊讶的太棒了!

现在的问题是参数<options>,因为它包含具有相同名称(<s_option><extra_option>)的子参数。这些标签的值总是不同的(也就是说,没有特定的值列表,它们是由员工手动插入的),而且我不知道每个产品有多少。我读到将它们存储为数组并不是那么好,但如果它是唯一可以得到它的简单解决方案。

3 个答案:

答案 0 :(得分:7)

我在这种情况下解决问题的方法是:

  1. 在数据库中创建相应的一组相应表格,然后通过从给定的XML中提取建模来表示公司的产品模型。

  2. 创建并使用计划的每日同步作业,该作业可能会执行少量SQL命令,以便通过解析将产品XML添加到创建的表中来刷新数据或引入新数据。

  3. 更加实用:

    • 对于数据库的,我可以根据您的XML轻松识别要创建的三个表,查看黄色标记的元素:

      1. Products
      2. ProductsOptions
      3. ProductsImages

    Exported Products Diagram

    此图表基于从您的XML 生成的XSD创建)


    所有其余的可以被视为Products表中的常规列,因为它们仅构成1-1关系。

    接下来,在数据库中创建所需的表(您可以使用XSD2DB Schema转换器工具创建DDL脚本,我手动完成):

    <强> companydb.products

    CREATE TABLE companydb.products (
      Id INT(11) NOT NULL,
      Version INT(11) DEFAULT NULL,
      InsertDate DATETIME DEFAULT NULL,
      Warrenty TINYINT(1) DEFAULT NULL,
      Price DECIMAL(19, 2) DEFAULT NULL,
      ModelCode INT(11) DEFAULT NULL,
      ModelColor VARCHAR(10) DEFAULT NULL,
      Model VARCHAR(255) DEFAULT NULL,
      ModelSize VARCHAR(10) DEFAULT NULL,
      InternalColor VARCHAR(10) DEFAULT NULL,
      InternalSize VARCHAR(10) DEFAULT NULL,
      PRIMARY KEY (Id)
    )
    ENGINE = INNODB
    CHARACTER SET utf8
    COLLATE utf8_general_ci
    COMMENT = 'Company''s Products';
    

    <强> companydb.productsimages

    CREATE TABLE companydb.productimages (
      Id INT(11) NOT NULL AUTO_INCREMENT,
      ProductId INT(11) DEFAULT NULL,
      Size VARCHAR(10) DEFAULT NULL,
      FileName VARCHAR(255) DEFAULT NULL,
      PRIMARY KEY (Id),
      CONSTRAINT FK_productsimages_products_Id FOREIGN KEY (ProductId)
        REFERENCES companydb.products(Id) ON DELETE RESTRICT ON UPDATE RESTRICT
    )
    ENGINE = INNODB
    AUTO_INCREMENT = 1
    CHARACTER SET utf8
    COLLATE utf8_general_ci
    COMMENT = 'Products'' Images';
    

    <强> companydb.productsoptions

    CREATE TABLE companydb.productoptions (
      Id INT(11) NOT NULL AUTO_INCREMENT,
      ProductId INT(11) DEFAULT NULL,
      Type VARCHAR(255) DEFAULT NULL,
      `Option` VARCHAR(255) DEFAULT NULL,
      PRIMARY KEY (Id),
      CONSTRAINT FK_producstsoptions_products_Id FOREIGN KEY (ProductId)
        REFERENCES companydb.products(Id) ON DELETE RESTRICT ON UPDATE RESTRICT
    )
    ENGINE = INNODB
    AUTO_INCREMENT = 1
    CHARACTER SET utf8
    COLLATE utf8_general_ci;
    

    • 对于要进行的同步作业流程,您可以轻松创建MySql event并使用Event Scheduler来控制它,我创建了所需的{{1调用你在下面找到的存储过程(event),看看:
      

    CREATE DEFINER ='root'@'localhost'EVENT   companydb.ProductsDataSyncEvent在每个'1'天开始计划   '2014-06-13 01:27:38'评论'同步产品表   产品XML'DO BEGIN SET @productsXml =   LOAD_FILE( 'C:/MySqlXmlSync/products.xml');呼叫   SyncProductsDataFromXML(@productsXml);结束;   ALTER EVENT companydb.ProductsDataSyncEvent ENABLE

    现在有趣的部分正在发生,这里是同步存储过程(注意上面SyncProductsDataFromXML如何调用它):

    event

    你完成了,这是这个过程的最终预期结果: enter image description here


    enter image description here


    enter image description here

    注意:我已将整个代码提交到我的一个GitHub存储库:XmlSyncToMySql

    <强>更新

    由于您的XML数据可能比CREATE DEFINER = 'root'@'localhost' PROCEDURE companydb.SyncProductsDataFromXML(IN productsXml MEDIUMTEXT) BEGIN DECLARE totalProducts INT; DECLARE productIndex INT; SET totalProducts = ExtractValue(productsXml, 'count(//export_management/product)'); SET productIndex = 1; WHILE productIndex <= totalProducts DO SET @productId = CAST(ExtractValue(productsXml, 'export_management/product[$productIndex]/@id') AS UNSIGNED); INSERT INTO products(`Id`, `Version`, InsertDate, Warrenty, Price, ModelCode, Model, ModelColor, ModelSize, InternalColor, InternalSize) VALUES( @productId, ExtractValue(productsXml, 'export_management/product[$productIndex]/version'), ExtractValue(productsXml, 'export_management/product[$productIndex]/insert_date'), CASE WHEN (ExtractValue(productsXml, 'export_management/product[$productIndex]/warrenty')) <> 'false' THEN 1 ELSE 0 END, CAST(ExtractValue(productsXml, 'export_management/product[$productIndex]/price') as DECIMAL), ExtractValue(productsXml, 'export_management/product[$productIndex]/model/code'), ExtractValue(productsXml, 'export_management/product[$productIndex]/model/model'), ExtractValue(productsXml, 'export_management/product[$productIndex]/model/color'), ExtractValue(productsXml, 'export_management/product[$productIndex]/model/size'), ExtractValue(productsXml, 'export_management/product[$productIndex]/internal/color'), ExtractValue(productsXml, 'export_management/product[$productIndex]/internal/size') ); SET @totalImages = ExtractValue(productsXml, 'count(//export_management/product[$productIndex]/images/image)'); SET @imageIndex = 1; WHILE (@imageIndex <= @totalImages) DO INSERT INTO productimages(ProductId, Size, FileName) VALUES(@productId, 'small', EXTRACTVALUE(productsXml, 'export_management/product[$productIndex]/images/image[$@imageIndex]/small')); SET @imageIndex = @imageIndex + 1; END WHILE; SET @totalStandardOptions = ExtractValue(productsXml, 'count(//export_management/product[$productIndex]/options/s_option)'); SET @standardOptionIndex = 1; WHILE (@standardOptionIndex <= @totalStandardOptions) DO INSERT INTO productoptions(ProductId, `Type`, `Option`) VALUES(@productId, 'Standard Option', EXTRACTVALUE(productsXml, 'export_management/product[$productIndex]/options/s_option[$@standardOptionIndex]')); SET @standardOptionIndex = @standardOptionIndex + 1; END WHILE; SET @totalExtraOptions = ExtractValue(productsXml, 'count(//export_management/product[$productIndex]/options/extra_option)'); SET @extraOptionIndex = 1; WHILE (@extraOptionIndex <= @totalExtraOptions) DO INSERT INTO productoptions(ProductId, `Type`, `Option`) VALUES(@productId, 'Extra Option', EXTRACTVALUE(productsXml, 'export_management/product[$productIndex]/options/extra_option[$@extraOptionIndex]')); SET @extraOptionIndex = @extraOptionIndex + 1; END WHILE; SET productIndex = productIndex + 1; END WHILE; END 字段允许的最大数据大,因此我已将TEXT参数更改为productsXml。看看这个答案,它概述了各种文本数据类型的最大允许大小: Maximum length for MYSQL type text

答案 1 :(得分:1)

由于这有点像集成工作,我建议使用临时格式的多遍,多步骤程序,不仅可以轻松导入到mysql中,而且还可以帮助您解决此集成所带来的问题用小步骤测试解决方案。

如果您可以将可以或可以在XML导出中表达的树结构展平为具有固定命名属性的产品列表,则此过程很有效。

  • 使用XML中的xpath查询查询所有产品元素,迭代产品结果
  • 查询与上一个查询相关的产品上下文节点的所有产品属性。每个属性再次使用一个xpath。
  • 将每个产品的所有属性的结果作为一行存储到CSV文件中。
  • 将文件名也存储在CSV中(基本名称),但文件存储在它自己的文件夹中
  • 以.sql文件的形式创建mysql表的DDL
  • 针对mysql命令行运行.sql文件。
  • 通过mysql命令行将CSV文件导入该表。

你应该在几小时内得到快速的结果。如果由于属性具有多个值(您在问题中称为数组)而无法将产品映射到单行,请考虑将这些转换为JSON字符串,如果您无法阻止它们掉落(只是希望你不需要在开头展示复杂的数据)。这样做会违反目标普通表格,但是正如你所描述的那样,Mysql表只是中间的,我会瞄准数据库中数据结构的简单性,否则会在网站上查询简单快速的显示将造成下一个负担。

所以我的建议主要是:将树结构转换为(更多)平面列表,以简化转换和更容易显示模板。

在这里使用中间格式也可以让你在出现问题时重播。

它还允许您更轻松地模拟整个模板。

Alterantive也可以将每个项目的XML存储在数据库中(将块保存在第二个表中,这样就可以将varchar(可变长度)文件保留在第一个表中)并保留其他列(平面) )引用要查询的列。如果它需要模板化需求,那么将XML转换为SimpleXMLElement通常非常好,因为它是一个结构化的非原始数据类型作为视图对象,您可以遍历和循环选项。与JSON类似,但保持XML不会破坏格式边界,XML也可以表达比JSON更多的结构。

答案 2 :(得分:0)

您采取了以技术为中心的方法。我认为从一开始就考虑功能规范是明智的。

有一个简单的业务类Product的UML类图是有帮助的。在业务看到它们时显示其属性。所以:

  • 模型与产品有何关系?一个产品可以有多个型号,反之亦然吗?
  • 内部元素中存储了哪种数据?特别是:内部颜色和尺寸如何与模特的颜色和尺寸不同?

特别是关于网络应用程序:

  • Web应用程序是唯一对此导出感兴趣的应用程序吗?
  • Web应用程序是否需要关注版本控制或只显示最新的可用版本?
  • Web应用程序有哪些特定选项。像折扣房产或供应商名称财产或其他?
  • 产品详细信息页面应该是什么样的,需要在哪里显示哪些数据?
  • 网站上是否有其他页面显示产品信息,以及它们列出的产品信息?

然后,您将知道Web应用程序需要哪些属性(如Product表中的列)和(可能)哪些属性可以简单地存储在数据库中的一个大型XML blob中。