Mysql Perl和XPath:数据库表中缺少条目
我想从xml文件中提取数据,并将其导入到MariaDB/MySQL数据库中。xml文件是:Mysql Perl和XPath:数据库表中缺少条目,mysql,xml,perl,xpath,mariadb,Mysql,Xml,Perl,Xpath,Mariadb,我想从xml文件中提取数据,并将其导入到MariaDB/MySQL数据库中。xml文件是: Perl代码是: 使用严格; 使用警告; 使用DBI; 使用XML::XPath; 使用XML::XPath::XMLParser; 我的$xp=XML::XPath->new(文件名=>“animals4.XML”); #我的$xp=XML::XPath->new(ioref=>\*数据); my$dbh=DBI->connect(“DBI:mysql:test”、“user”、“pw”{Raise
Perl代码是:
使用严格;
使用警告;
使用DBI;
使用XML::XPath;
使用XML::XPath::XMLParser;
我的$xp=XML::XPath->new(文件名=>“animals4.XML”);
#我的$xp=XML::XPath->new(ioref=>\*数据);
my$dbh=DBI->connect(“DBI:mysql:test”、“user”、“pw”{RaiseError=>1,PrintError=>0})
或者死“Fehler beim Verbidungsaufbau zum MariaDB服务器:”。“$DBI::err-<$DBI::errstr\n”;
对于我的$row1($xp->findnodes('//row1s/row1')){
printf“Level---row1\“name\”给出了:%s\n“,$row1->getAttribute(“name”);
对于我的$row2($row1->findnodes('.//row2s/row2')){
printf“Level row2\”type\”给出了:%s\n“,$row2->getAttribute(“type”);
printf“Level row2\”size\”给出了:%s\n“,$row2->getAttribute(“size”);
$dbh->do(
“在animal4(名称、类别、类型、大小)中插入值(?、、?、?)”,
未定义,
$row1->getAttribute(“名称”),
$row1->getAttribute(“类别”),
$row2->getAttribute(“类型”),
$row2->getAttribute(“大小”)
)或死“执行期间出错:”。“$DBI::err->$DBI::errstr(动物$DBI::state)\n”;
}
}
终端输出为:
Level---row1“name”给出:fox
第2级“类型”给出:1
级别行2“大小”给出:10
第2级“类型”给出:2
级别行2“大小”给出:8
级别---第1行“名称”给出:马
第2级“类型”给出:3
级别行2“大小”给出:100
级别---第1行“名称”给出:bee
级别---第1行“名称”给出:黄蜂
这正是我所期望的。但该表包含以下条目:
名称类别类型大小
狐狸哺乳动物110
狐狸哺乳动物28
马类哺乳动物3100
蜜蜂和黄蜂被错过了。有人能帮我解决这个问题吗?我想知道为什么会发生这种情况,因为终端的输出是正常的
谢谢你的帮助
以下是表格的代码:
创建表test01.animal4(
名称VARCHAR(50)默认为空
,类别VARCHAR(50)默认为空
,键入整数默认值为空
,大小整数默认为空
);
这是的后续问题。根据您的代码,只有当第二次查询(对于$row1下的节点)返回结果时,才会发生DB写入:
for my $row1 ( $xp->findnodes('//row1s/row1') ){
for my $row2 ( $row1->findnodes('.//row2s/row2') ) {
$dbh->do("INSERT INTO animal4 (name, category,type,size) VALUES(?,?,?,?)"
[...]
) or die ;
}
}
如果没有$row2节点,则不存在数据库写入
如果希望在不考虑是否存在$row2节点的情况下进行数据库写入,则需要将数据库写入移出该for循环,即:
for my $row1 ( $xp->findnodes('//row1s/row1') ){
# get name and category here
my $name = $row1->getAttribute('name');
my $cat = $row1->getAttribute('category');
my $row2set = $row1->find('row2s/row2'); ## creates a Nodeset object
if ($row2set->size > 0) {
## we found nodes!!
foreach my $row2 ($row2set->get_nodelist) {
# get size and type here
my $type = $row2->getAttribute('type');
my $size = $row2->getAttribute('size');
# write to db
}
} else {
## no row2 nodes found.
## write to db - just write the row1 values; type and size will be undefined.
}
}
节点集文档:
关于设置变量和范围的简要说明
作用域是指实体(变量、子例程、对象等)在Perl代码中可见和可访问的位置;设置实体的范围有助于封装它们,并防止数据或函数在程序的每个部分的任何地方都可用
作用域是使用代码结构设置的,例如子例程、循环、包、对象——由大括号({
和}
分隔的任何代码块)。Perl(和许多其他语言)的标准做法是在进入块时增加缩进,在离开块时减少缩进;这样,您可以在阅读代码时相当容易地确定范围
使用my
将变量(或函数、对象等)的范围设置为仅限于设置变量的代码块;e、 g
for my $row1 ( $xp->findnodes('//row1s/row1') ){
# $row1 is available inside this code block
my $row2set = $row1->find('row2s/row2');
# $row2set is now available inside this code block
if ($row2set->size > 0) {
my $size = $row2set->size;
# $size is now available inside this code block
foreach my $row2 ($row2set->get_nodelist) {
# $row2 is available inside this code block
# we can also access $row1, $row2set, $size
}
# we can access $row1, $row2set, $size
# $row2 is out of scope, i.e. we cannot access it
say "The value of row2 is $row2";
# Perl will complain 'Global symbol "$row2" requires explicit package name'
}
# we can access $row1 and $row2set
# $size and $row2 are out of scope
}
# $row1, $row2set, $size, and $row2 are out of scope
回到您的代码,假设您决定设置变量$name
、$category
、$type
和$size
,以捕获数据并将其写入数据库。您必须确保正确设置变量的范围,否则它们将存储不适当的数据。例如:
# declare all our variables
my ($name, $cat, $type, $size);
for my $row1 ( $xp->findnodes('//row1s/row1') ){
# we can set $name and $cat from the data in row1:
$name = $row1->getAttribute('name');
$cat = $row1->getAttribute('category');
my $row2set = $row1->find('row2s/row2');
if ($row2set->size > 0) {
foreach my $row2 ($row2set->get_nodelist) {
# row2 gives us the type and size info
$type = $row2->getAttribute('type');
$size = $row2->getAttribute('size');
# "say" prints a string and adds a "\n" to the end,
# so it's very handy for debugging
say "row2s found: name: $name; category: $cat; type: $type; size: $size";
}
} else {
say "row2s empty: name: $name; category: $cat; type: $type; size: $size";
}
}
这为我们提供了以下输出:
row2s found: name: fox; category: mammal; type: 1; size: 10
row2s found: name: fox; category: mammal; type: 2; size: 8
row2s found: name: horse; category: mammal; type: 3; size: 100
row2s empty: name: bee; category: insect; type: 3; size: 100
row2s empty: name: wasp; category: insect; type: 3; size: 100
这是因为$type
和$size
的范围被设置为整个代码块,并且值在row1循环和内部row2循环的每次迭代之间保留。蜜蜂和黄蜂没有大小和类型的值,因此使用前一种动物的值
有许多不同的方法可以解决此问题,但最有效的方法可能是:
my $db_insert = $dbh->prepare('INSERT INTO animal4 (name, category, type, size) VALUES (?, ?, ?, ?)');
for my $row1 ( $xp->findnodes('//row1s/row1') ){
my $row2set = $row1->find('row2s/row2');
if ($row2set->size > 0) {
foreach my $row2 ($row2set->get_nodelist) {
# for debugging
say "row2s found: name: " . $row1->getAttribute('name') .
"; category: " . $row1->getAttribute('category') .
"; type: " . $row2->getAttribute('type') .
"; size: " . $row2->getAttribute('size');
$db_insert->execute( $row1->getAttribute('name'),
$row1->getAttribute('category'),
$row2->getAttribute('type'),
$row2->getAttribute('size') );
}
} else {
# for debugging
say "row2s empty: name: " . $row1->getAttribute('name') .
"; category: " . $row1->getAttribute('category') .
"; type: NOT SET" .
"; size: NOT SET";
$db_insert->execute( $row1->getAttribute('name'),
$row1->getAttribute('category'),
undef,
undef );
}
}
您已经有了解释和修复,但我建议进行以下更改
- 您应该
准备
插入到
SQL语句中,然后
的开销要大得多在循环中执行它<代码>执行
(/
)XPath构造非常昂贵,您应该将其保留在不知道元素在文档中的位置的情况下,这是非常罕见的。在这种情况下,子代或self::node()
元素位于row1
,而/database/row1s/row1
元素位于相对于该行的row2
row2s/row2
- 如果要在带引号的字符串中使用引号字符,则使用不同的分隔符要干净得多。例如
比“我的名字是\“$name\”
qq{我的名字是“$name”}
use strict;
use warnings;
use XML::XPath;
use DBI;
my $xp = XML::XPath->new( filename => 'animals4.xml' );
my $dbh = DBI->connect(
'DBI:mysql:test', 'user', 'pw',
{ RaiseError => 1, PrintError => 0}
) or die "Fehler beim Verbidungsaufbau zum MariaDB-Server: $DBI::err -< $DBI::errstr\n";
my $insert_animal = $dbh->prepare('INSERT INTO animal4 (name, category, type, size) VALUES (?, ?, ?, ?)');
for my $row1 ( $xp->findnodes('/database/row1s/row1') ) {
my $name = $row1->getAttribute('name');
my $category = $row1->getAttribute('category');
printf qq{Level --- row1 "name" gives: $name\n};
my @row2 = $xp->findnodes('row2s/row2', $row1);
if ( @row2 ) {
for my $row2 ( @row2 ) {
my $type = $row2->getAttribute('type');
my $size = $row2->getAttribute('size');
print qq{Level row2 "type" gives: $type\n};
print qq{Level row2 "size" gives: $size\n};
$insert_animal->execute($name, $category, $type, $size);
}
}
else {
$insert_animal->execute($name, $category, undef, undef);
}
}
无需添加节点集:
my@row2s=$xp->find('.//row2s/row2');如果(@row2s){我的$row2(@row2s){…}其他{…}
@alien谢谢你的代码和解释。真奇怪。当我使用你的代码时,每只动物从所有动物那里得到类型和大小:狐狸(1/10,2/8,3/100);马(1/10,2/8,3/100)、蜜蜂(1/10,2/8,3/100)、黄蜂(1/10,2/8,3/100))。@ikegami感谢这个缩写。我试过了,但是我得到了一条消息(在:Level1--row1“name”给出:fox之后):“找不到对象methid”getAttribute,通过paclage“XML::XPath::NodeSet”在
Level --- row1 "name" gives: fox
Level row2 "type" gives: 1
Level row2 "size" gives: 10
Level row2 "type" gives: 2
Level row2 "size" gives: 8
Level --- row1 "name" gives: horse
Level row2 "type" gives: 3
Level row2 "size" gives: 100
Level --- row1 "name" gives: bee
Level --- row1 "name" gives: wasp