use XML::LibXML;
use Data::Dumper;
#parsing file
my $dom = XML::LibXML->new->parse_file('sample.xml');
#print file to make sure it looks ok
print $dom, "\n";
#finds shortnames
my $sn = $dom->findnodes('//shortName');
print 'ShortName: '.$sn, "\n";
#finds dbRefernce ids that are of type EC
my $ids = $dom->findnodes('//dbReference[@type="EC"]/@id');
my $number =()= $ids =~ /\./gi;
print 'Result: '.$ids, "\n";
#finds sequences that have a length
my $seq = $dom->findnodes('//sequence[@length>1]');
$seq =~ s/" "/"\n"/;
print 'Sequence: '.$seq, "\n";
我有这个代码,它接受所有短名称,EC类型的dbReferences,以及具有长度的序列并打印它们。我有sample.xml(https://www.dropbox.com/s/dq8ir9f22cnfwrz/Sample.xml) 这是我需要解析的最大文件。但我一直在使用oneentry.xml(https://www.dropbox.com/s/6nxexfig46sw0v6/oneentry.xml),它只是较大列表中的一个条目。
问题是代码适用于一个条目并打印出来:
ShortName: 17-beta-HSD 53-alpha-HSD type 2DD-3DD3PGFS
Result: 1.-.-.-1.1.1.3571.1.1.1121.1.1.1881.1.1.2391.1.1.641.3.1.20
Sequence: MDSKHQCVKLNDGHFMPVLGFGTYAPPEVPRSKALEVTKLAIEAGFRHIDSAHLYNNEEQ VGLAIRSKIADGSVKREDIFYTSKLWSTFHRPELVRPALENSLKKAQLDYVDLYLIHSPM SLKPGEELSPTDENGKVIFDIVDLCTTWEAMEKCKDAGLAKSIGVSNFNRRQLEMILNKP GLKYKPVCNQVECHPYFNRSKLLDFCKSKDIVLVAYSALGSQRDKRWVDPNSPVLLEDPV LCALAKKHKRTPALIALRYQLQRGVVVLAKSYNEQRIRQNVQVFEFQLTAEDMKAIDGLD RNLHYFNSDSFASHPNYPYSDEY
但它不会为整个文件输出任何内容。与使脚本功能不相同的两个文件有什么不同?
答案 0 :(得分:4)
这两个文件有一个重要区别。您的小文件oneentry.xml
的开头如下:
<uniprot>
<entry dataset="Swiss-Prot" created="1995-11-01" modified="2014-05-14" version="156">
<accession>P42330</accession>
<accession>A8K2V0</accession>
...
但你的大号Sample.xml
略有不同:
<uniprot xmlns="http://uniprot.org/uniprot"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://uniprot.org/uniprot
http://www.uniprot.org/support/docs/uniprot.xsd">
<entry dataset="Swiss-Prot" created="1995-11-01" modified="2014-05-14" version="156">
<accession>P42330</accession>
<accession>A8K2V0</accession>
...
较大的文件声明默认命名空间:xmlns="http://uniprot.org/uniprot"
而较小的命名空间不会。这将影响节点的选择。如果您的XML文件具有默认命名空间(其标签不需要前缀),则无关紧要。 XPath数据模型忽略了这一点。 XPath表达式假定元素选择器属于 no-namespace ,除非它们显式限定为前缀,该前缀映射到文件中声明的命名空间对于那些元素。
有两种方法可以解决这个问题:
注册命名空间
这是推荐的解决方案,因为它可以保证您正在提取正确的节点。你需要选择一个前缀。前缀可以是任何合法的XML标识符uniprot
,u
,up
- 您决定。您需要获取文档的XPath上下文:
my $context = XML::LibXML::XPathContext->new( $dom->documentElement() );
$context->registerNs('u', 'http://uniprot.org/uniprot');
现在所有你的XPath选择器必须加前缀。替换
//shortName
//dbReference[@type="EC"]/@id
//sequence[@length>1]
与
//u:shortName
//u:dbReference[@type="EC"]/@id
//u:sequence[@length>1]
(假设您选择u
作为前缀。)
这不是这种情况,但如果你有一个包含多个步骤的路径,则需要在每个步骤中限定元素选择器。例如,如果你必须使用绝对表达式,你会写:
/u:uniprot/u:entry/u:reference[16]/u:citation/u:dbReference[@type="EC"]/@id
忽略命名空间
这是一种替代解决方案,可以有时被使用(通常用于小的明确选择,我认为不是你的情况)。您选择所有元素(使用任何元素通配符:*
),然后使用标记名称的 local 部分进行过滤谓词(使用local-name()
函数。对于此解决方案,您不必注册任何名称空间。您只需更改表达式。
//*[local-name() = 'shortName']
//*[local-name() = 'dbReference'][@type="EC"]/@id
//*[local-name() = 'sequence'][@length>1]
此解决方案的问题在于,如果您有两个具有相同本地名称且位于不同名称空间的元素,那么它们也将被选中。假设您没有任何冲突名称,此解决方案的优点是您可以在文件中使用它,具有名称空间的文件和没有名称空间的文件。