使用PHP将多级XML加载到MYSQL中

时间:2015-07-16 01:23:07

标签: php mysql xml xpath

我有以下需要导入MySQL的XML文件(作为.xml)。我面临的问题是它是多层次的,我不知道如何将信息输入数据库。

我可以将一个级别加载到数据库中,但随着每个“患者”的节点发生变化,我假设需要使用IF语句。

数据库输出应如下所示:

link_id          postcode          age          sex          atsi          status          measure_type          measure_done          service_date          measure_value          bp_diastolic          bp_systolic          practice_id     extract_date
-------          --------          ---          ---          ----          ------          ------------          ------------          ------------          -------------          ------------          -----------          -----------     ------------
Patient 1        1234              50           2            4             c               BP                    True                  22011999              null                   80                    128                  DEMO            2015-07-13T14:45:55.876Z
Patient 1        1234              50           2            4             c               CHOLESTEROL           True                  05061998              7.2                    null                  null                 DEMO            2015-07-13T14:45:55.876Z
Patient 1        1234              50           2            4             c               HAEMOGLOBIN           True                  05061998              134                    null                  null                 DEMO            2015-07-13T14:45:55.876Z
Patient 2        4567              21           1            2             P               BP                    True                  18062014              null                   72                    135                  DEMO            2015-07-13T14:45:55.876Z
Patient 2        4567              21           1            2             P               HEIGHT                True                  22011999              161.0                  null                  null                 DEMO            2015-07-13T14:45:55.876Z
Patient 2        4567              21           1            2             P               LDL                   True                  05061998              5.00                   null                  null                 DEMO            2015-07-13T14:45:55.876Z

每个单独的测量需要它在数据库中自己的行,并从数据和患者节点中提取信息。

我尝试过使用XPath但未成功。

这是XML:

    <?xml version="1.0" encoding="windows-1252"?>
<MedicalMicrodata xmlns="URL HERE">
  <data>
    <practice_id>DEMO</practice_id>
    <extract_date>2015-07-13T14:45:55.876Z</extract_date>
    <population_count>123</population_count>
    <extractor_details>Demonstration 123</extractor_details>
    <patient>
      <link_id>Patient 1</link_id>
      <postcode>1234</postcode>
      <age>50</age>
      <sex>2</sex>
      <atsi>4</atsi>
      <active>False</active>
      <status>C</status>
      <measurements>
        <bp>
          <bp_diastolic>80</bp_diastolic>
          <bp_done>True</bp_done>
          <bp_service_date>22011999</bp_service_date>
          <bp_systolic>128</bp_systolic>
        </bp>
        <cholesterol>
          <cholesterol_done>True</cholesterol_done>
          <cholesterol_service_date>05061998</cholesterol_service_date>
          <cholesterol_value>7.2</cholesterol_value>
        </cholesterol>
        <haemoglobin>
          <haemoglobin_done>True</haemoglobin_done>
          <haemoglobin_service_date>05061998</haemoglobin_service_date>
          <haemoglobin_value>134.00</haemoglobin_value>
        </haemoglobin>
      </measurements>
    </patient>
    <patient>
      <link_id>Patient 2</link_id>
      <postcode>4567</postcode>
      <age>21</age>
      <sex>1</sex>
      <atsi>2</atsi>
      <active>False</active>
      <status>P</status>
      <measurements>
        <bp>
          <bp_diastolic>72</bp_diastolic>
          <bp_done>True</bp_done>
          <bp_service_date>18062014</bp_service_date>
          <bp_systolic>135</bp_systolic>
        </bp>
        <height>
          <height_done>True</height_done>
          <height_service_date>22011999</height_service_date>
          <height_value>161.0</height_value>
        </height>
        <ldl>
          <ldl_done>True</ldl_done>
          <ldl_service_date>05061998</ldl_service_date>
          <ldl_value>5.00</ldl_value>
        </ldl>
      </measurements>
    </patient>
  </data>
</MedicalMicrodata>

XPATH代码示例

$header_path=$xml->xpath("data");
$patient_path=$xml->xpath("data/patient");
$bp_path=$xml->xpath("data/patient/measurements/bp");
$cholesterol_path=$xml->xpath("data/patient/measurements/cholesterol");
$haemoglobin_path=$xml->xpath("data/patient/measurements/haemoglobin");
$hba1c_path=$xml->xpath("data/patient/measurements/hba1c");
$hdl_path=$xml->xpath("data/patient/measurements/hdl");
$height_path=$xml->xpath("data/patient/measurements/height");
$ldl_path=$xml->xpath("data/patient/measurements/ldl");
$rbg_path=$xml->xpath("data/patient/measurements/random_blood_glucose");
$triglycerides_path=$xml->xpath("data/patient/measurements/triglycerides");
$weight_path=$xml->xpath("data/patient/measurements/weight");

if (!$header_path) {
    foreach ($header_path as $header) {

        $extract_date = $header["extract_date"];
        $practice_id = $header["practice_id"];

        echo $practice_id;

            if ($patient_path) {

                $postcode = $patient["postcode"];
                $age = $patient["age"];
                $sex = $patient["sex"];
                $atsi = $patient["atsi"];
                $status = $patient["status"];


                    // BP                    
                    if ($bp_path) {

                        foreach ($bp_path as $bp) {

                            $measure_done = $bp["bp_done"];
                            $service_date = $bp["bp_service_date"];
                            $bp_diastolic = $bp["bp_diastolic"];
                            $bp_systolic = $bp["bp_systolic"];

                            $sql = "INSERT INTO 'nkpi_pat_measure' (postcode, age, sex, atsi, status, measure_type, measure_done, service_date, bp_diastolic, bp_systolic, practice_id, extract_date) 
                                    VALUES ('$postcode', '$age','$sex','$atsi','$status','BP','$measure_done', '$service_date','$bp_diastolic','$bp_systolic','$practice_id','$extract_date')";
                                    $result = $sqlconn->prepare($sql);
                                    $result->execute();

                        }
                    }

非常感谢任何帮助。

提前谢谢。

阿德里安。

1 个答案:

答案 0 :(得分:1)

根据您的表结构,它主要是来自此处的肘部油脂:为患者对象创建数据传输对象(php类),为测量创建测量对象,以及2个表:

表格患者:

  

表患者有地址信息和其他个人信息

CREATE TABLE patient (
patient_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
{other patient data}
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4; /* While we are there, lets save some storage space */

为患者添加唯一索引,以便患者记录只能插入一次。

表格测量:

  

表测量有测量结果。

这都是标准化的: 测量结果存储为:

 <measurements>
    <bp>
      <bp_diastolic>80</bp_diastolic>
      <bp_done>True</bp_done>
      <bp_service_date>22011999</bp_service_date>
      <bp_systolic>128</bp_systolic>
    </bp>
    <cholesterol>
      <cholesterol_done>True</cholesterol_done>
      <cholesterol_service_date>05061998</cholesterol_service_date>
      <cholesterol_value>7.2</cholesterol_value>
    </cholesterol>
    <haemoglobin>
      <haemoglobin_done>True</haemoglobin_done>
      <haemoglobin_service_date>05061998</haemoglobin_service_date>
      <haemoglobin_value>134.00</haemoglobin_value>
    </haemoglobin>
  </measurements>

CREATE TABLE measurements(
measurements_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
patient_id INT NOT NULL,
done BOOLEAN,
service_date DATE,
medical_data_identifier VARCHAR(200),
measured_value TEXT,
FOREIGN KEY (patient_id) REFERENCES patient(patient_id)
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4; /* While we are there, lets save some storage space */

技巧1:n:1患者,多次测量,无需重复任何数据。

第二个技巧是在medical_data_identifier中:

  

medical_data_identifier的结构如下:   *每次测试1个或多个记录。

这将导致收缩压/舒张压的2条记录。 &GT; medical_data_identifier =收缩压

  

值= 128

     

medical_data_identifier =舒张压

     

值= 72

风险:1天多次测试。为了对抗你可以做其他事情:将测试存储为json或xml:

  

medical_data_identifier =血压

     

值= 80128

这取决于选择使用内容的用途。还有其他解决方案: XML或JSON格式列(为此使用mariadb而不是mysql:100%兼容,但只有更多选项)。

或标识测试父数据的父列。

或者在获得具有3个表的1:N:M数据模型之间的测试标识符表:

  • 患者
  • 测试
  • 测量

它们之间存在关键关系。

然后你只需编写一段php代码来插入所有这些内容。