Perl XML::LibXML 用法
Perl XML::LibXML usage
我在使用 XML::LibXML 时遇到了一些问题,我想知道是否有办法做我想做的事情,或者我的 XML 是否应该更改。
目前,我的 XML 看起来像:
<fftg>
<actions>
<rename>
<mandatory>0</mandatory>
<other_things_here />
</rename>
<transfer>
<mandatory>0</mandatory>
<protocol>SFTP</protocol>
<other_things_here />
</transfer>
<transfer>
<mandatory>1</mandatory>
<protocol>FTP</protocol>
<other_things_here />
</transfer>
<archive>
<mandatory>1</mandatory>
<other_things_here />
</archive>
<rename>
<mandatory>1</mandatory>
<other_things_here />
</rename>
</actions>
</fftg>
如你所见,在"actions"下可以有不同类型的动作(每种动作有1个或多个动作,每个动作下有不同的东西)
我想浏览每个操作并根据操作执行特定的操作。
我的问题是:由于有多个相同类型的动作,脚本无法正常工作并覆盖之前的相同类型的动作,或者特定动作上的循环在每个动作上重新循环同类
示例 1:
foreach my $transfer ($doc->findnodes('/fftg')) {
# Browse Actions
foreach my $action ($doc->findnodes('/fftg/actions/*')) {
my $action_name = $action->nodeName();
my $actiontype = ucfirst($action->nodeName());
print "executing action $action_name ..\n";
# Browse action details
foreach my $action_details ($doc->findnodes('/fftg/actions/'.$action_name)) {
for my $detail ($action_details->findnodes('./*')) {
print $detail->nodeName(), ": ", $detail->textContent(), "\n";
}
}
print "-------------\n";
}
}
结果 1:
executing action rename ..
mandatory: 0
other_things_here:
mandatory: 1
other_things_here:
-------------
executing action transfer ..
mandatory: 0
protocol: SFTP
other_things_here:
mandatory: 1
protocol: FTP
other_things_here:
-------------
executing action transfer ..
mandatory: 0
protocol: SFTP
other_things_here:
mandatory: 1
protocol: FTP
other_things_here:
-------------
executing action archive ..
mandatory: 1
other_things_here:
-------------
executing action rename ..
mandatory: 0
other_things_here:
mandatory: 1
other_things_here:
-------------
如您所见,这个结果是错误的,因为在每个 "action type" 中(这是好的,已检测到),它在同类的每个动作上重新循环。
这是由于:
foreach my $action_details ($doc->findnodes('/fftg/actions/'.$action_name)) {
我该怎么做才能达到我想要的效果? (如果可能的话不改变 XML)
我想要的是:
executing action rename ..
mandatory: 0
other_things_here:
-------------
executing action transfer ..
mandatory: 0
protocol: SFTP
other_things_here:
-------------
executing action transfer ..
mandatory: 1
protocol: FTP
other_things_here:
-------------
executing action archive ..
mandatory: 1
other_things_here:
-------------
executing action rename ..
mandatory: 1
other_things_here:
-------------
谢谢
附带说明一下,我想我可以更改我的 XML 并使用类似的东西来轻松修复它(但我不知道哪一个是三者之间的最佳选择),但是我想避免下面这两个,因为 XSD 之后很难生成(我想要每个动作类型的特定选项):
<fftg>
<actions>
<action>
<type>rename</type>
<mandatory>0</mandatory>
<other_things_here />
</action>
<action>
<type>transfer</type>
<mandatory>0</mandatory>
<protocol>SFTP</protocol>
<other_things_here />
<action>
<action>
<type>transfer</type>
<mandatory>0</mandatory>
<protocol>FTP</protocol>
<other_things_here />
<action>
<action>
<type>archive</type>
<mandatory>0</mandatory>
<other_things_here />
<action>
<action>
<type>rename</type>
<mandatory>0</mandatory>
<other_things_here />
<action>
</actions>
</fftg>
或
<fftg>
<actions>
<action type="rename">
<mandatory>0</mandatory>
<other_things_here />
</action>
<action type="transfer">
<mandatory>0</mandatory>
<protocol>SFTP</protocol>
<other_things_here />
<action>
<action type="transfer">
<mandatory>0</mandatory>
<protocol>FTP</protocol>
<other_things_here />
<action>
<action type="archive">
<mandatory>0</mandatory>
<other_things_here />
<action>
<action type="rename">
<mandatory>0</mandatory>
<other_things_here />
<action>
</actions>
</fftg>
再次感谢
问候,
首先,您在 $doc
上调用 findnodes,这意味着您的 XPath 表达式是针对文档根节点计算的。其次,您使用的 XPath 表达式以“/”开头,因此再次以 top-level 节点为根。这样,当您致电时:
$doc->findnodes('/fftg/actions/rename')
这意味着 "give me every <rename/>
element that is child of <actions/>
element that is child of <fftg/>
element that is root node of document",因此,您将获得在文档中找到的每个 <rename/>
节点。
而且循环太多了。第一个是多余的,因为可能只有一个根元素。两个循环应该可以工作(一个在 <action/>
children 上,另一个在 children 上):
for my $action ($doc->findnodes('/fftg/actions/*')) {
print "executing ", $action->nodeName(), "\n";
for my $detail ($action->findnodes('./*')) {
print $detail->nodeName(), ": ", $detail->textContent(), "\n";
}
}
我在使用 XML::LibXML 时遇到了一些问题,我想知道是否有办法做我想做的事情,或者我的 XML 是否应该更改。
目前,我的 XML 看起来像:
<fftg>
<actions>
<rename>
<mandatory>0</mandatory>
<other_things_here />
</rename>
<transfer>
<mandatory>0</mandatory>
<protocol>SFTP</protocol>
<other_things_here />
</transfer>
<transfer>
<mandatory>1</mandatory>
<protocol>FTP</protocol>
<other_things_here />
</transfer>
<archive>
<mandatory>1</mandatory>
<other_things_here />
</archive>
<rename>
<mandatory>1</mandatory>
<other_things_here />
</rename>
</actions>
</fftg>
如你所见,在"actions"下可以有不同类型的动作(每种动作有1个或多个动作,每个动作下有不同的东西)
我想浏览每个操作并根据操作执行特定的操作。
我的问题是:由于有多个相同类型的动作,脚本无法正常工作并覆盖之前的相同类型的动作,或者特定动作上的循环在每个动作上重新循环同类
示例 1:
foreach my $transfer ($doc->findnodes('/fftg')) {
# Browse Actions
foreach my $action ($doc->findnodes('/fftg/actions/*')) {
my $action_name = $action->nodeName();
my $actiontype = ucfirst($action->nodeName());
print "executing action $action_name ..\n";
# Browse action details
foreach my $action_details ($doc->findnodes('/fftg/actions/'.$action_name)) {
for my $detail ($action_details->findnodes('./*')) {
print $detail->nodeName(), ": ", $detail->textContent(), "\n";
}
}
print "-------------\n";
}
}
结果 1:
executing action rename ..
mandatory: 0
other_things_here:
mandatory: 1
other_things_here:
-------------
executing action transfer ..
mandatory: 0
protocol: SFTP
other_things_here:
mandatory: 1
protocol: FTP
other_things_here:
-------------
executing action transfer ..
mandatory: 0
protocol: SFTP
other_things_here:
mandatory: 1
protocol: FTP
other_things_here:
-------------
executing action archive ..
mandatory: 1
other_things_here:
-------------
executing action rename ..
mandatory: 0
other_things_here:
mandatory: 1
other_things_here:
-------------
如您所见,这个结果是错误的,因为在每个 "action type" 中(这是好的,已检测到),它在同类的每个动作上重新循环。
这是由于:
foreach my $action_details ($doc->findnodes('/fftg/actions/'.$action_name)) {
我该怎么做才能达到我想要的效果? (如果可能的话不改变 XML)
我想要的是:
executing action rename ..
mandatory: 0
other_things_here:
-------------
executing action transfer ..
mandatory: 0
protocol: SFTP
other_things_here:
-------------
executing action transfer ..
mandatory: 1
protocol: FTP
other_things_here:
-------------
executing action archive ..
mandatory: 1
other_things_here:
-------------
executing action rename ..
mandatory: 1
other_things_here:
-------------
谢谢
附带说明一下,我想我可以更改我的 XML 并使用类似的东西来轻松修复它(但我不知道哪一个是三者之间的最佳选择),但是我想避免下面这两个,因为 XSD 之后很难生成(我想要每个动作类型的特定选项):
<fftg>
<actions>
<action>
<type>rename</type>
<mandatory>0</mandatory>
<other_things_here />
</action>
<action>
<type>transfer</type>
<mandatory>0</mandatory>
<protocol>SFTP</protocol>
<other_things_here />
<action>
<action>
<type>transfer</type>
<mandatory>0</mandatory>
<protocol>FTP</protocol>
<other_things_here />
<action>
<action>
<type>archive</type>
<mandatory>0</mandatory>
<other_things_here />
<action>
<action>
<type>rename</type>
<mandatory>0</mandatory>
<other_things_here />
<action>
</actions>
</fftg>
或
<fftg>
<actions>
<action type="rename">
<mandatory>0</mandatory>
<other_things_here />
</action>
<action type="transfer">
<mandatory>0</mandatory>
<protocol>SFTP</protocol>
<other_things_here />
<action>
<action type="transfer">
<mandatory>0</mandatory>
<protocol>FTP</protocol>
<other_things_here />
<action>
<action type="archive">
<mandatory>0</mandatory>
<other_things_here />
<action>
<action type="rename">
<mandatory>0</mandatory>
<other_things_here />
<action>
</actions>
</fftg>
再次感谢 问候,
首先,您在 $doc
上调用 findnodes,这意味着您的 XPath 表达式是针对文档根节点计算的。其次,您使用的 XPath 表达式以“/”开头,因此再次以 top-level 节点为根。这样,当您致电时:
$doc->findnodes('/fftg/actions/rename')
这意味着 "give me every <rename/>
element that is child of <actions/>
element that is child of <fftg/>
element that is root node of document",因此,您将获得在文档中找到的每个 <rename/>
节点。
而且循环太多了。第一个是多余的,因为可能只有一个根元素。两个循环应该可以工作(一个在 <action/>
children 上,另一个在 children 上):
for my $action ($doc->findnodes('/fftg/actions/*')) {
print "executing ", $action->nodeName(), "\n";
for my $detail ($action->findnodes('./*')) {
print $detail->nodeName(), ": ", $detail->textContent(), "\n";
}
}