草庐IT

mysql - 将 XML 文件同步到 MySQL 数据库

coder 2023-10-15 原文

我的公司使用内部管理软件来存储产品。他们想将所有的产品转移到一个 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> )。这些标签的值总是不同的(也就是说,没有特定的值列表,它们是由员工手动插入的)而且我也不知道每个产品有多少。我读到将它们存储为数组不太好,但如果这是唯一简单的解决方案,我可以得到它。

最佳答案

在您的情况下,我处理问题的方式是:

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

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

为了更加实际:

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

    1. 产品
    2. 产品选项
    3. 产品图片

(此图表基于从您的 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为了控制它,我创建了所需的事件,它调用了一个存储过程,您将在下面找到它 (SyncProductsDataFromXML),看:

CREATE DEFINER = 'root'@'localhost' EVENT companydb.ProductsDataSyncEvent ON SCHEDULE EVERY '1' DAY STARTS '2014-06-13 01:27:38' COMMENT 'Synchronize Products table with Products XMLs' DO BEGIN SET @productsXml = LOAD_FILE('C:/MySqlXmlSync/products.xml'); CALL SyncProductsDataFromXML(@productsXml); END; ALTER EVENT companydb.ProductsDataSyncEvent ENABLE

现在有趣的部分开始了,这是同步存储过程(注意上面的 event 是如何调用它的):

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

大功告成,这是此过程的最终预期结果:



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

更新:

因为您的 XML 数据可能大于 TEXT 字段允许的最大值,我已将 productsXml 参数更改为 MEDIUMTEXT .查看此答案,其中概述了各种文本数据类型的最大允许大小: Maximum length for MYSQL type text

关于mysql - 将 XML 文件同步到 MySQL 数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24080516/

有关mysql - 将 XML 文件同步到 MySQL 数据库的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  5. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  6. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  7. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  8. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  9. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  10. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

随机推荐