【问题标题】:C# to Extract XML Segments and Insert into SQLC# 提取 XML 段并插入 SQL
【发布时间】:2021-03-10 06:20:12
【问题描述】:

我是 C# 的新手,但我对 SQL 有一定的了解

我在一个文件夹中有 1000 个 XML 文件。我需要提取某些元素并将它们存储在 SQL 中。 XMl 将包含我需要存储在 SQL 中的带有后代的段。 举个例子,下面是一个仓单123456,有多个orderline,每个orderline都有一个product/code段。

我有一个包含 5 列的 SQL 表 - Client、Warehouse、OrderReference、CustomerReference、Type 和 ProductCode。

例如

<UniversalShipment xmlns="http://www.cargowise.com/Schemas/Universal/2011/11" version="1.1">
    <Shipment>
        <Order>
            <OrderNumber>123456</OrderNumber>
            <ClientReference>abcdefg</ClientReference>
            <DocketSubType>
                <Code>ORD</Code>
                <Description>ORDER</Description>
            </DocketSubType>
            <Warehouse>
                <Name>Seb's Test Warehouse</Name>
            </Warehouse>
            <OrderLineCollection Content="Complete">
                <OrderLine>
                    <Product>
                        <Code>8011</Code>
                    </Product>
                </OrderLine>
                    <OrderLine>
                        <Product>
                            <Code>8044</Code>
                        </Product>
                    </OrderLine>
                    <OrderLine>
                        <Product>
                            <Code>8043</Code>
                        </Product>
                    </OrderLine>
                    <OrderLine>
                        <Product>
                            <Code>8042</Code>
                        </Product>
                    </OrderLine>
                    <OrderLine>
                        <Product>
                            <Code>8054</Code>
                        </Product>
                    </OrderLine>
                    <OrderLine>
                        <Product>
                            <Code>8018</Code>
                        </Product>
                    </OrderLine>
                    <OrderLine>
                        <Product>
                            <Code>8061</Code>
                        </Product>
                    </OrderLine>
                </OrderLineCollection>
            </Order>
            <OrganizationAddressCollection>
                <OrganizationAddress>
                    <AddressType>SendersLocalClient</AddressType>
                    <CompanyName>The Client</CompanyName>
                </OrganizationAddress>
            </OrganizationAddressCollection>
        </Shipment>
    </UniversalShipment>

我有以下工作,但它只会将 1 行发布到 SQL - 第一个订单行,它不会循环通过订单行段

using System;
using System.Linq;
using System.Xml.Linq;
using System.Data;
using System.Data.SqlClient;
using System.Collections.Generic;

namespace Load_XML_To_SQL
{
    class Program
    {
        static void Main(string[] args)
        {
            XDocument xmlDocument = XDocument.Load(@"C:\Users\sebby\Desktop\MLL\XML to SQL\sample.xml");
            XNamespace ns = xmlDocument.Root.GetDefaultNamespace();
          
                Orders Order = new Orders();
                
                Order.Client = xmlDocument.Elements(ns + "UniversalShipment")
                                              .Elements(ns + "Shipment")
                                              .Elements(ns + "OrganizationAddressCollection")
                                              .Elements(ns + "OrganizationAddress")
                                              .Elements(ns + "CompanyName")
                                              .FirstOrDefault()?.Value;
                Order.Warehouse = xmlDocument.Elements(ns + "UniversalShipment")
                                              .Elements(ns + "Shipment")
                                              .Elements(ns + "Order")
                                              .Elements(ns + "Warehouse")
                                              .Elements(ns + "Name")
                                              .FirstOrDefault()?.Value;

                 Order.OrderReference = xmlDocument.Elements(ns + "UniversalShipment")
                                              .Elements(ns + "Shipment")
                                              .Elements(ns + "Order")
                                              .Elements(ns + "OrderNumber")
                                              .FirstOrDefault()?.Value;
                Order.CustomerReference = xmlDocument.Elements(ns + "UniversalShipment")
                                              .Elements(ns + "Shipment")
                                              .Elements(ns + "Order")
                                              .Elements(ns + "ClientReference")
                                              .FirstOrDefault()?.Value;
                 Order.DocketSubType = xmlDocument.Elements(ns + "UniversalShipment")
                                              .Elements(ns + "Shipment")
                                              .Elements(ns + "Order")
                                              .Elements(ns + "Type")
                                              .Elements(ns + "Code")
                                              .FirstOrDefault()?.Value;
            Order.ProductCode = xmlDocument.Elements(ns + "UniversalShipment")
                                          .Elements(ns + "Shipment")
                                          .Elements(ns + "Order")
                                          .Elements(ns + "OrderLineCollection")
                                          .Elements(ns + "OrderLine")
                                          .Elements(ns + "Product")
                                          .Elements(ns + "Code")
                                          .FirstOrDefault()?.Value;
          
                string connetionString = null;
                SqlConnection connection;
                SqlCommand command;
                string sql = null;
                SqlDataReader dataReader;
                connetionString = "Data Source=My Server;Initial Catalog=MyDB;User ID=MyUser;Password=MyPassword";
                sql = "Exec InsertXML @Client='" + Order.Client +
                                   "',@Warehouse = '" + Order.Warehouse +
                                   "',@OrderReference='" + Order.OrderReference +
                                   "',@CustomerReference='" + Order.CustomerReference +
                                   "',@DocketSubtype='" + Order.DocketSubType +
                                   "'";
                
                connection = new SqlConnection(connetionString);
                try
                {
                    connection.Open();
                    command = new SqlCommand(sql, connection);
                    dataReader = command.ExecuteReader();
                    while (dataReader.Read())
                    {
                        Console.WriteLine(dataReader.GetValue(0) + " - " + dataReader.GetValue(1) + " - " + dataReader.GetValue(2));
                    }
                    dataReader.Close();
                    command.Dispose();
                    connection.Close();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
        }

    }
    

    internal class Orders
    {
        public string Client { get; set; }
        public string Warehouse{ get; set; }
        public string OrderReference { get; set; }
        public string CustomerReference { get; set; }
        public string DocketSubType { get; set; }
        public string ProductCode { get; set; }
    


}

    

【问题讨论】:

    标签: c# sql xml


    【解决方案1】:

    我更改了代码,使其对 sql 注入变得安全,添加了资源处理,并按照普遍接受的规范更改了名称。

    using System.Collections.Generic;
    using System.Data;
    using System.Data.SqlClient;
    using System.IO;
    using System.Linq;
    using System.Xml.Linq;
    
    namespace ConApp5
    {
        public class Program
        {
            // The connection string must be defined in a single place of the class, not in every method.
            private static string _connectionString = @"...";
    
            static void Main()
            {
                // Don't lump the code together, break it down into methods with talking names.
                foreach (var path in Directory.EnumerateFiles(".", "*.xml"))
                {
                    Order order = ParseXml(path);
                    InsertData(order);
                }
            }
            
            static Order ParseXml(string path)
            {
                XDocument xmlDocument = XDocument.Load(path);
                XNamespace ns = xmlDocument.Root.GetDefaultNamespace();
    
                var shipmentNode = xmlDocument.Element(ns + "UniversalShipment").Element(ns + "Shipment");
                // Reuse the same node.
                var orderNode = shipmentNode.Element(ns + "Order");
    
                Order order = new Order();
    
                order.Client = shipmentNode
                    .Element(ns + "OrganizationAddressCollection")
                    .Element(ns + "OrganizationAddress")
                    .Element(ns + "CompanyName").Value;
    
                order.Warehouse = orderNode
                    .Element(ns + "Warehouse")
                    .Element(ns + "Name").Value;
    
                order.OrderReference = orderNode
                    .Element(ns + "OrderNumber").Value;
    
                order.CustomerReference = orderNode
                    .Element(ns + "ClientReference").Value;
    
                order.DocketSubType = orderNode
                    .Element(ns + "DocketSubType")
                    .Element(ns + "Code").Value;
    
                order.ProductCodes = orderNode
                    .Element(ns + "OrderLineCollection")
                    .Elements(ns + "OrderLine")
                    .Elements(ns + "Product")
                    .Elements(ns + "Code")
                    .Select(x => x.Value).ToList();
    
                return order;
            }
    
            static void InsertData(Order order)
            {
                // We must release resources such as the connection and the command. `using` operator do it.
                using (var connection = new SqlConnection(_connectionString))
                {
                    connection.Open();
                    string sql = "InsertXML"; // stored procedure name
    
                    using (var command = new SqlCommand(sql, connection))
                    {
                        // Explicitly specify that the command calls a stored procedure.
                        command.CommandType = CommandType.StoredProcedure;
    
                        // The names of the sql parameters are the same as in the stored procedure.
                        // Instead of SqlDbType.NVarChar, specify the real type.
    
                        command.Parameters.Add("Client", SqlDbType.NVarChar).Value = order.Client;
                        command.Parameters.Add("Warehouse", SqlDbType.NVarChar).Value = order.Warehouse;
                        command.Parameters.Add("OrderReference", SqlDbType.NVarChar).Value = order.OrderReference;
                        command.Parameters.Add("CustomerReference", SqlDbType.NVarChar).Value = order.CustomerReference;
                        command.Parameters.Add("DocketSubtype", SqlDbType.NVarChar).Value = order.DocketSubType;
    
                        var parameterCode = command.Parameters.Add("Code", SqlDbType.NVarChar);
    
                        foreach (var code in order.ProductCodes)
                        {
                            parameterCode.Value = code;
    
                            _ = command.ExecuteNonQuery();
                        }
                    }
                }
            }
    
        }
    }
    
    internal class Order // singular
    {
        public string Client { get; set; }
        public string Warehouse { get; set; }
        public string OrderReference { get; set; }
        public string CustomerReference { get; set; }
        public string DocketSubType { get; set; }
        public List<string> ProductCodes { get; set; } // plural
    }
    

    另外你必须更改Order类中的类型,将sql参数的类型更改为数据库表中使用的类型。

    【讨论】:

    • 嗨,亚历克斯。我已经使用了你的代码,它就像一个梦一样工作。我现在一直在试图弄清楚如何使用它来运行特定文件夹中的所有 xml 文件,而不仅仅是 1 个 xml。但是当我这样做时我会破坏你的代码:(有什么建议吗?
    • @SebSoum - 已更新。 PS:不要在cmets中问新问题。改为编辑您的帖子。或者创建一个新主题。
    【解决方案2】:

    您需要遍历 xmlDocument。请尝试下面的代码,虽然我不确定是否可以以相同的方式访问 xe.Elements。

    using System;
    using System.Linq;
    using System.Xml.Linq;
    using System.Data;
    using System.Data.SqlClient;
    using System.Collections.Generic;
    
    namespace WindowsFormsApp1
    {
        class Program
        {
            static void Main(string[] args)
            {
                XDocument xmlDocument = XDocument.Load(@"C:\Users\sebby\Desktop\MLL\XML to SQL\sample.xml");
                XNamespace ns = xmlDocument.Root.GetDefaultNamespace();
    
                Orders Order = new Orders();
    
    
                foreach (XElement xe in xmlDocument.Nodes())
                {
    
    
                    Order.Client = xe.Elements(ns + "UniversalShipment")
                                                  .Elements(ns + "Shipment")
                                                  .Elements(ns + "OrganizationAddressCollection")
                                                  .Elements(ns + "OrganizationAddress")
                                                  .Elements(ns + "CompanyName")
                                                  .FirstOrDefault()?.Value;
                    Order.Warehouse = xe.Elements(ns + "UniversalShipment")
                                                  .Elements(ns + "Shipment")
                                                  .Elements(ns + "Order")
                                                  .Elements(ns + "Warehouse")
                                                  .Elements(ns + "Name")
                                                  .FirstOrDefault()?.Value;
    
                    Order.OrderReference = xe.Elements(ns + "UniversalShipment")
                                                 .Elements(ns + "Shipment")
                                                 .Elements(ns + "Order")
                                                 .Elements(ns + "OrderNumber")
                                                 .FirstOrDefault()?.Value;
                    Order.CustomerReference = xe.Elements(ns + "UniversalShipment")
                                                  .Elements(ns + "Shipment")
                                                  .Elements(ns + "Order")
                                                  .Elements(ns + "ClientReference")
                                                  .FirstOrDefault()?.Value;
                    Order.DocketSubType = xe.Elements(ns + "UniversalShipment")
                                                 .Elements(ns + "Shipment")
                                                 .Elements(ns + "Order")
                                                 .Elements(ns + "Type")
                                                 .Elements(ns + "Code")
                                                 .FirstOrDefault()?.Value;
                    Order.ProductCode = xe.Elements(ns + "UniversalShipment")
                                                  .Elements(ns + "Shipment")
                                                  .Elements(ns + "Order")
                                                  .Elements(ns + "OrderLineCollection")
                                                  .Elements(ns + "OrderLine")
                                                  .Elements(ns + "Product")
                                                  .Elements(ns + "Code")
                                                  .FirstOrDefault()?.Value;
    
                    string connetionString = null;
                    SqlConnection connection;
                    SqlCommand command;
                    string sql = null;
                    SqlDataReader dataReader;
                    connetionString = "Data Source=My Server;Initial Catalog=MyDB;User ID=MyUser;Password=MyPassword";
                    sql = "Exec InsertXML @Client='" + Order.Client +
                                       "',@Warehouse = '" + Order.Warehouse +
                                       "',@OrderReference='" + Order.OrderReference +
                                       "',@CustomerReference='" + Order.CustomerReference +
                                       "',@DocketSubtype='" + Order.DocketSubType +
                                       "'";
    
                    connection = new SqlConnection(connetionString);
                    try
                    {
                        connection.Open();
                        command = new SqlCommand(sql, connection);
                        dataReader = command.ExecuteReader();
                        while (dataReader.Read())
                        {
                            Console.WriteLine(dataReader.GetValue(0) + " - " + dataReader.GetValue(1) + " - " + dataReader.GetValue(2));
                        }
                        dataReader.Close();
                        command.Dispose();
                        connection.Close();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex);
                    }
                }
            }
        }
    
    }
    
    
    internal class Orders
    {
        public string Client { get; set; }
        public string Warehouse { get; set; }
        public string OrderReference { get; set; }
        public string CustomerReference { get; set; }
        public string DocketSubType { get; set; }
        public string ProductCode { get; set; }
    
    }
    

    【讨论】:

    • 嗨卡子。谢谢你快速的回复。它仍然只向表中添加 1 行,但现在它始终为空值(即客户端为空,仓库为空等)。产品代码为 NULL
    • 如果有帮助,我在每个 xe 之后添加了一些“Consol.WriteLine(Order.Client)”,但它没有在控制台中打开
    • 其实我的回答是错误的,你只需要遍历 OrderLineCollection。让我改一下答案。
    猜你喜欢
    • 1970-01-01
    • 2019-09-07
    • 2019-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-10
    相关资源
    最近更新 更多