我公司使用内部管理软件存储产品。他们希望将所有产品转置到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>
)的子参数。这些标签的值总是不同的(也就是说,没有特定的值列表,它们是由员工手动插入的),而且我不知道每个产品有多少。我读到将它们存储为数组并不是那么好,但如果它是唯一可以得到它的简单解决方案。
答案 0 :(得分:7)
我在这种情况下解决问题的方法是:
在数据库中创建相应的一组相应表格,然后通过从给定的XML中提取建模来表示公司的产品模型。
创建并使用计划的每日同步作业,该作业可能会执行少量SQL命令,以便通过解析将产品XML添加到创建的表中来刷新数据或引入新数据。
更加实用:
对于数据库的表,我可以根据您的XML轻松识别要创建的三个表,查看黄色标记的元素:
Products
ProductsOptions
ProductsImages
(此图表基于从您的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;
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
你完成了,这是这个过程的最终预期结果:
注意:我已将整个代码提交到我的一个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导出中表达的树结构展平为具有固定命名属性的产品列表,则此过程很有效。
你应该在几小时内得到快速的结果。如果由于属性具有多个值(您在问题中称为数组)而无法将产品映射到单行,请考虑将这些转换为JSON字符串,如果您无法阻止它们掉落(只是希望你不需要在开头展示复杂的数据)。这样做会违反目标普通表格,但是正如你所描述的那样,Mysql表只是中间的,我会瞄准数据库中数据结构的简单性,否则会在网站上查询简单快速的显示将造成下一个负担。
所以我的建议主要是:将树结构转换为(更多)平面列表,以简化转换和更容易显示模板。
在这里使用中间格式也可以让你在出现问题时重播。
它还允许您更轻松地模拟整个模板。
Alterantive也可以将每个项目的XML存储在数据库中(将块保存在第二个表中,这样就可以将varchar(可变长度)文件保留在第一个表中)并保留其他列(平面) )引用要查询的列。如果它需要模板化需求,那么将XML转换为SimpleXMLElement通常非常好,因为它是一个结构化的非原始数据类型作为视图对象,您可以遍历和循环选项。与JSON类似,但保持XML不会破坏格式边界,XML也可以表达比JSON更多的结构。
答案 2 :(得分:0)
您采取了以技术为中心的方法。我认为从一开始就考虑功能规范是明智的。
有一个简单的业务类Product的UML类图是有帮助的。在业务看到它们时显示其属性。所以:
特别是关于网络应用程序:
然后,您将知道Web应用程序需要哪些属性(如Product表中的列)和(可能)哪些属性可以简单地存储在数据库中的一个大型XML blob中。