diff --git a/CMakeLists.txt b/CMakeLists.txt
index fd45cfa..c0ade3e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,6 +22,7 @@ set(PROJECT_SOURCES
         src/config.h src/config.cpp public_def.cpp resource.qrc
         resource/ico.rc src/attribute_edit.ui src/attribute_edit.h
         src/attribute_edit.cpp flatgray.qrc
+        src/data_edit.h src/data_edit.cpp src/data_edit.ui
 )
 
 if (MSVC)
diff --git a/MainWidget.cpp b/MainWidget.cpp
index f0124d6..81749a7 100644
--- a/MainWidget.cpp
+++ b/MainWidget.cpp
@@ -3,6 +3,7 @@
 #include <QSettings>
 #include <QFile>
 #include <QKeyEvent>
+#include "src/data_edit.h"
 #include "./ui_MainWidget.h"
 
 constexpr std::size_t g_OnePage = 100;
@@ -28,6 +29,9 @@ MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget
     ui->btnSave->setEnabled(false);
     ui->edAllPage->setEnabled(false);
     ui->cbCaseSensitive->setChecked(false);
+    ui->btnRead->setFixedWidth(100);
+    ui->btnSave->setFixedWidth(100);
+    ui->btnExit->setFixedWidth(100);
 
     connect(ui->btnSelectFile, &QPushButton::clicked, this, [&]() {
         QString file = CUtil::select_file(this, u8"请选择xml文件", u8"XML(*.xml);;所有文件 (*)");
@@ -42,10 +46,21 @@ MainWidget::MainWidget(QWidget* parent) : QWidget(parent), ui(new Ui::MainWidget
     connect(ui->btnSave, &QPushButton::clicked, this, [&]() { save(); });
     connect(ui->btnExit, &QPushButton::clicked, this, [&]() { QApplication::exit(0); });
     connect(ui->btnReset, &QPushButton::clicked, this, &MainWidget::reset);
+    connect(ui->btnExport, &QPushButton::clicked, this, &MainWidget::copy_multi_data);
     connect(ui->btnPagePre, &QPushButton::clicked, this, [&]() {
         unsigned int cur = ui->edCurPage->text().toUInt();
         push_content(current_, cur - 1);
     });
+    connect(ui->btnImport, &QPushButton::clicked, this, [&]() {
+        CDataEdit edit;
+        edit.is_import_ = true;
+        edit.exec();
+        if (edit.is_import_sucess_) {
+            CUtil::msg(this, u8"导入成功");
+        } else {
+            CUtil::msg(this, u8"导入失败");
+        }
+    });
     connect(ui->btnPageNext, &QPushButton::clicked, this, [&]() {
         unsigned int cur = ui->edCurPage->text().toUInt();
         push_content(current_, cur + 1);
@@ -302,7 +317,7 @@ void MainWidget::item_changed_handle(QTableWidgetItem* item)
     int col = item->column();
 
     QString    xml_key = tab_widget_->item(row, 0)->text();
-    Element_t* result = get_element_bykey(xml_key);
+    Element_t* result = get_element_by_key(xml_key);
     if (result == nullptr) {
         return;
     }
@@ -329,7 +344,7 @@ void MainWidget::copy_select_line()
         return;
     }
 
-    Element_t* target = get_element_bykey(cur_item->text());
+    Element_t* target = get_element_by_key(cur_item->text());
     if (target == nullptr) {
         return;
     }
@@ -423,7 +438,7 @@ void MainWidget::init_menu()
             return;
         }
 
-        Element_t* target = get_element_bykey(cur_item->text());
+        Element_t* target = get_element_by_key(cur_item->text());
         if (target == nullptr) {
             return;
         }
@@ -463,7 +478,7 @@ void MainWidget::del_select_line()
     if (item == nullptr) {
         return;
     }
-    Element_t* target = get_element_bykey(item->text());
+    Element_t* target = get_element_by_key(item->text());
     if (target == nullptr) {
         return;
     }
@@ -489,7 +504,7 @@ Element_t* MainWidget::get_current_select_key()
     if (item == nullptr) {
         return ret;
     }
-    ret = get_element_bykey(item->text());
+    ret = get_element_by_key(item->text());
     return ret;
 }
 
@@ -515,7 +530,7 @@ void MainWidget::reset()
     push_content(current_);
 }
 
-tinyxml2::XMLElement* MainWidget::get_element_bykey(const QString& key)
+tinyxml2::XMLElement* MainWidget::get_element_by_key(const QString& key)
 {
     Element_t* ret = nullptr;
     for (const auto& ele : current_) {
@@ -530,6 +545,17 @@ tinyxml2::XMLElement* MainWidget::get_element_bykey(const QString& key)
     return ret;
 }
 
+Element_t* MainWidget::get_element_by_row(int row)
+{
+    Element_t* ret = nullptr;
+    if (row < 0 || !tab_widget_ || row >= tab_widget_->rowCount()) {
+        return ret;
+    }
+    QTableWidgetItem* item = tab_widget_->item(row, 0);
+    ret = get_element_by_key(item->text());
+    return ret;
+}
+
 void MainWidget::sort_by_repeat(std::vector<Element_t*>& vec)
 {
     struct SElement_t {
@@ -564,4 +590,30 @@ void MainWidget::sort_by_repeat(std::vector<Element_t*>& vec)
     for (const auto& item : turn_vec) {
         vec.push_back(item.ele);
     }
-}
\ No newline at end of file
+}
+
+void MainWidget::copy_multi_data()
+{
+    if (tab_widget_ == nullptr) {
+        return;
+    }
+    QModelIndexList indexList = tab_widget_->selectionModel()->selectedRows();
+    if (indexList.size() < 1) {
+        CUtil::msg(this, u8"无选择数据");
+        return;
+    }
+    QString ret;
+    for (int i = 0; i < indexList.size(); ++i) {
+        Element_t* e = get_element_by_row(indexList[i].row());
+        if (e == nullptr) {
+            continue;
+        }
+        tinyxml2::XMLPrinter printer;
+        e->Accept(&printer);
+        ret.append(printer.CStr());
+    }
+
+    CDataEdit edit;
+    edit.set_data(ret);
+    edit.exec();
+}
diff --git a/MainWidget.h b/MainWidget.h
index 35b0c8e..185e4d5 100644
--- a/MainWidget.h
+++ b/MainWidget.h
@@ -45,13 +45,15 @@ private:
     void ele_update_gui(Element_t* target, int row);
     void show_custom_menu();
     void sort_by_repeat(std::vector<Element_t*>& vec);
+    void copy_multi_data();
 
 protected:
     void closeEvent(QCloseEvent* event);
     void keyPressEvent(QKeyEvent* event);
 
 private:
-    Element_t*        get_element_bykey(const QString& key);
+    Element_t*        get_element_by_key(const QString& key);
+    Element_t*        get_element_by_row(int row);
     Element_t*        get_current_select_key();
     QTableWidgetItem* get_current_select_item();
 
diff --git a/MainWidget.ui b/MainWidget.ui
index 8a27ca9..36d0cdf 100644
--- a/MainWidget.ui
+++ b/MainWidget.ui
@@ -51,13 +51,6 @@
         </property>
        </widget>
       </item>
-      <item>
-       <widget class="QPushButton" name="btnExit">
-        <property name="text">
-         <string>退出</string>
-        </property>
-       </widget>
-      </item>
      </layout>
     </widget>
    </item>
@@ -68,14 +61,14 @@
      </property>
      <layout class="QHBoxLayout" name="horizontalLayout_2">
       <item>
-       <widget class="QPushButton" name="pushButton_2">
+       <widget class="QPushButton" name="btnExport">
         <property name="text">
          <string>导出选择行</string>
         </property>
        </widget>
       </item>
       <item>
-       <widget class="QPushButton" name="pushButton_3">
+       <widget class="QPushButton" name="btnImport">
         <property name="text">
          <string>导入行</string>
         </property>
@@ -177,6 +170,13 @@
    </item>
    <item>
     <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QPushButton" name="btnExit">
+       <property name="text">
+        <string>退出</string>
+       </property>
+      </widget>
+     </item>
      <item>
       <spacer name="horizontalSpacer_2">
        <property name="orientation">
diff --git a/src/data_edit.cpp b/src/data_edit.cpp
new file mode 100644
index 0000000..c054344
--- /dev/null
+++ b/src/data_edit.cpp
@@ -0,0 +1,73 @@
+#include "data_edit.h"
+#include "ui_data_edit.h"
+#include <QScreen>
+#include <QClipboard>
+#include <tinyxml2.h>
+#include "../public_def.h"
+
+CDataEdit::CDataEdit(QWidget* parent) : QDialog(parent), ui(new Ui::CDataEdit)
+{
+    ui->setupUi(this);
+
+    // setMinimumWidth(600);
+    setWindowTitle(u8"源属性编辑");
+
+    connect(ui->btnExit, &QPushButton::clicked, this, [&]() { close(); });
+    connect(ui->btnAdd, &QPushButton::clicked, this, [&]() { import_data(); });
+    connect(ui->btnCopy, &QPushButton::clicked, this, [&]() {
+        QClipboard* clip = QApplication::clipboard();
+        clip->setText(ui->plainTextEdit->toPlainText());
+    });
+}
+
+CDataEdit::~CDataEdit()
+{
+    delete ui;
+}
+
+void CDataEdit::set_data(const QString& data)
+{
+    data_ = data;
+}
+
+void CDataEdit::import_data()
+{
+    QString data = ui->plainTextEdit->toPlainText();
+    if (data.trimmed().isEmpty()) {
+        CUtil::msg(this, u8"内容为空");
+        return;
+    }
+    QStringList list = data.trimmed().split("\n");
+    for (int i = 0; i < list.size(); ++i) {
+        const QString& item = list[i];
+        if (item.trimmed().isEmpty()) {
+            continue;
+        }
+        tinyxml2::XMLDocument doc;
+        doc.Parse(item.toStdString().c_str());
+        if (doc.Error()) {
+            CUtil::msg(this, u8"不是合法的xml语句。");
+            return;
+        }
+    }
+}
+
+void CDataEdit::showEvent(QShowEvent* event)
+{
+    show_before();
+    QDialog::showEvent(event);
+}
+
+void CDataEdit::show_before()
+{
+    QScreen* primaryScreen = QGuiApplication::primaryScreen();
+    QRect    screenGeometry = primaryScreen->geometry();
+    setMinimumWidth(screenGeometry.width() * 0.8);
+    if (is_import_) {
+        ui->btnCopy->setVisible(false);
+    } else {
+        ui->btnAdd->setVisible(false);
+        ui->plainTextEdit->clear();
+        ui->plainTextEdit->appendPlainText(data_);
+    }
+}
diff --git a/src/data_edit.h b/src/data_edit.h
new file mode 100644
index 0000000..385d1ea
--- /dev/null
+++ b/src/data_edit.h
@@ -0,0 +1,35 @@
+#ifndef DATA_EDIT_H
+#define DATA_EDIT_H
+
+#include <QDialog>
+
+namespace Ui {
+class CDataEdit;
+}
+
+class CDataEdit : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit CDataEdit(QWidget* parent = nullptr);
+    ~CDataEdit();
+
+public:
+    void set_data(const QString& data);
+    void import_data();
+
+protected:
+    void showEvent(QShowEvent* event) override;
+    void show_before();
+
+public:
+    bool is_import_{false};
+    bool is_import_sucess_{false};
+
+private:
+    Ui::CDataEdit* ui;
+    QString        data_{};
+};
+
+#endif   // DATA_EDIT_H
diff --git a/src/data_edit.ui b/src/data_edit.ui
new file mode 100644
index 0000000..b4e8e2a
--- /dev/null
+++ b/src/data_edit.ui
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CDataEdit</class>
+ <widget class="QDialog" name="CDataEdit">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>643</width>
+    <height>407</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QPlainTextEdit" name="plainTextEdit"/>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="btnCopy">
+       <property name="text">
+        <string>复制</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="btnAdd">
+       <property name="text">
+        <string>添加</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="btnExit">
+       <property name="text">
+        <string>退出</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>