使用PHP将选项卡式文本转换为树(SQL将每行插入TreeNode表(TreeNodeID,ParentID,Title))

时间:2012-09-16 18:09:17

标签: php database automation screen-scraping arbor.js

我正在尝试使用ArborJS,尝试构建知识树。 Here是我的测试区域(左键单击以进入节点,右键单击以返回到开头)。我有“所有”的“人文与艺术”部分充实,所以我建议在那个区域进行游戏。

我正在从Wikipedia's List of Academic Disciplines article构建此树。

现在,我从一个mySQL表中提取数据(通过PHP)。表结构是TreeNodeID,ParentID,Title。 “TreeNodeID”是主键(自动增量),“ParentID”是节点的父节点,“Title”是应该在节点上显示的文本。

我现在在本文的第7页,共27页。我觉得我没有利用我的计算机自动完成手动输入过程的能力。

我刚刚制作了所有科目的文本文件。它采用以下格式:

Anthropology
    Biological Anthropology
        Forensic Anthropology
        Gene-Culture Coevolution
        Human Behavioral Ecology
    Anthropological Linguistics
        Synchronic Linguistics
        Diachronic Linguistics
        Ethnolinguistics
        Socioloinguistics
    Cultural Anthropology
        Anthropology of Religion
        Economic Anthropology
Archaelogy
...

如何使用PHP来完成此操作并填充我的数据库(每个节点使用正确的ParentID)?

更新#3:工作代码(由下面的正确答案给出)

<?php
//echo "Checkpoint 1";

$data = "
Social sciences
    Anthropology
        Biological anthropology
            Forensic anthropology
            Gene-culture coevolution
            Human behavioral ecology
            Human evolution
            Medical anthropology
            Paleoanthropology
            Population genetics
            Primatology
        Anthropological linguistics
            Synchronic linguistics (or Descriptive linguistics)
            Diachronic linguistics (or Historical linguistics)
            Ethnolinguistics
            Sociolinguistics
        Cultural anthropology
            Anthropology of religion
            Economic anthropology
            Ethnography
            Ethnohistory
            Ethnology
            Ethnomusicology
            Folklore
            Mythology
            Political anthropology
            Psychological anthropology
    Archaeology
        ...(goes on for a long time)
";

//echo "Checkpoint 2\n";

$lines = preg_split("/\n/", $data);

$parentids = array(0 => null);
$db = new PDO("host", 'username', 'pass');
$sql = 'INSERT INTO `TreeNode` SET ParentID = ?, Title = ?';
$stmt = $db->prepare($sql);

//echo "Checkpoint 3\n";

foreach ($lines as $line) {
    if (!preg_match('/^([\s]*)(.*)$/', $line, $m)) {
        continue;
    }
    $spaces = strlen($m[1]);
    //$level = intval($spaces / 4); //assumes four spaces per indent
    $level = strlen($m[1]); // if data is tab indented
    $title = $m[2];
    $parentid = ($level > 0 ? $parentids[$level - 1] : 1); //All "roots" are children of "Academia" which has an ID of "1";

    $rv = $stmt->execute(array($parentid, $title));

    $parentids[$level] = $db->lastInsertId();
    echo "inserted $parentid - " . $parentid . " title: " . $title . "\n";
}
?>

3 个答案:

答案 0 :(得分:1)

未经测试,但这应该适合您(使用PDO):

<?php

$data = "
Anthropology
    Biological Anthropology
        Forensic Anthropology
        Gene-Culture Coevolution
        Human Behavioral Ecology
    Anthropological Linguistics
        Synchronic Linguistics
        Diachronic Linguistics
        Ethnolinguistics
        Socioloinguistics
    Cultural Anthropology
        Anthropology of Religion
        Economic Anthropology
Archaelogy
";

$lines = preg_split("/\n/", $data);

$parentids = array(0 => null);

$sql = 'INSERT INTO `table` SET ParentID = ?, Title = ?';
$stmt = $db->prepare($sql);

foreach ($lines as $line) {
    if (!preg_match('/^([\s]*)(.*)$/', $line, $m)) {
        continue;
    }
    #$spaces = strlen($m[1]);
    #$level = intval($spaces / 4); # if data is space indented
    $level = strlen($m[1]); # assumes data is tab indented
    $title = $m[2];

    $parentid = $level > 0
        ? $parentids[$level - 1]
        null;

    $rv = $stmt->execute(array($parentid, $title));

    $parentids[$level] = $db->lastInsertId();
}

答案 1 :(得分:0)

我会说,如上所述,首先复制粘贴更容易缩进。然后解析它:

  • 读取每一行(一次一行),为您提供节点文本。
  • 每个缩进都是一个新子节点,因此prev节点是父ID
  • 检查dedents - 如果您保持一致或计算\t,则计算indent level。注意0-indent(root)。

这将允许您构建包含每个学科的关联数组。然后你解释那个。例如:

  • 获取所有根节点(root的第一个子节点,具体取决于节点)并为其提供增量ID parse_id
  • 从上面继续沿着数组,将parse_id分配给所有节点。
  • 然后开始将数据放入MySQL。与您一样,在数组中添加mysqli_insert_idparse_id,例如调用 db_id 。这应该用于将数据库中所需的parent_id与父项parse_id相关联。

假设您没有尝试检查常见研究或唯一节点文本,那应该足够简单。

答案 2 :(得分:0)

您可以尝试使用以下

// parser.php

<?php
include_once './vendor/autoload.php';

use Symfony\Component\DomCrawler\Crawler;

$crawler = new Crawler(file_get_contents('http://en.wikipedia.org/wiki/List_of_academic_disciplines'));

$texts = $crawler->filter('.tocnumber + .toctext');
$numbers = $crawler->filter('.tocnumber');


$last = '';

for ($i=0; $i < count($numbers); $i++) {
    $value = $numbers->eq($i)->text();
    if(!preg_match('/\d+.\d+/', $value)) {
        // is a root discipline
        $last = $texts->eq($i)->text();
    } else {
        // is a leaf discipline
        $disciplines[$last][$texts->eq($i)->text()] = $texts->eq($i)->text();
    }
}

var_dump($disciplines);

有了这个,你可以做更多像数据库或任何的持久化,并对其他DOM解析任务有用​​

我使用了CssSelector,Symfony Components的DomCrawler易于安装

composer.json

{
    "name": "wiki-parser",
    "require": {
        "php": ">=5.3.3",
        "symfony/dom-crawler": "2.1.0",
        "symfony/css-selector": "2.1.0"
    }
}
控制台中的

$ php composer.phar install

查看getcomposer