簡體   English   中英

如何使用XML :: LibXML查找不區分大小寫的節點

[英]How to find nodes case-insensitive using XML::LibXML

我需要在XML文件中找到不區分大小寫的節點。 以下代碼有效,但僅當所有元素都不為小寫時:

my $dom = XML::LibXML->new->parse_fh(*DATA);
my $xpc = XML::LibXML->XPathContext->new( $dom->documentElement );
my @invoices = $xpc->findnodes( "/ALLINVOICES/INVOICES/INVOICE" );

__DATA__
<ALLINVOICES>
  <INVOICES>
    <INVOICE number="12345">
       <CUSTOMER>Mr Fubar</CUSTOMER>
    </INVOICE>
  </INVOICES>
</ALLINVOICES>

如何修復它,使其也接受<allinvoices><invoices><invoice>

將元素名稱規范化為小寫的字符串預處理階段可能會幫助您:

my $xmlstring = '';
{
    local $/;
    $xmlstring = <DATA>;
}

#
# Turns all element names into lowercase.
# Works as well with uppercase ( replace lc with uc )
#
# !!! The usual caveats wrt processing semistructured data with regexen apply (ie. don't try more complex transformations purely by changing the regex pattern )
#
$xmlstring =~ s#(<[/]?[^/>[:space:]]+)#lc($1)#eg; # all element names

my $dom = XML::LibXML->new->parse_string( $xmlstring);
# ...

注意

提出的解決方案錯誤地處理了注釋和cdata部分(如@ikegami所指出)。 為了根據安全規格 ,元素名稱的第一個字符必須屬於以下字符類:

  [:_a-zA-Z\x{c0}-\x{d6}\x{d8}-\x{f6}\x{f8}-\x{ff}\x{0370}-\x{037d}\x{037f}-\x{1fff}\x{200c}\x{200d}\x{2070}-\x{218f}\x{2c00}-\x{2fef}\x{3001}-\x{d7ff}\x{f900}-\x{fdcf}\x{fdf0}-\x{fffd}\N{U+10000}-\n{U+EFFFF}]

這個怪物會插入[/]?之間[/]? 和上面代碼部分的regex模式中的[^/>[:space:]]* (遵守更改的重復修飾符)。

XML和XPath始終區分大小寫,因此您需要編寫將字符串轉換為大寫或小寫的代碼以進行比較。 我認為LibXML::XPathContext允許您注冊其他函數,以便您可以在Perl中編寫一個函數,從XPath調用該函數,並帶有要比較的節點和名稱,並根據需要返回true或false:

$xpc->registerFunction('tn', sub { my ($node,$name) = @_; if (lc($node->item(0)->localName) eq $name) { return XML::LibXML::Boolean->True; } else { return XML::LibXML::Boolean->False;} });

my @invoices = $xpath->findnodes('/*[tn(., "allinvoices")]/*[tn(., "invoices")]/*[tn(., "invoice")]');

但是,這僅比編寫注釋(很多)長XPath表達式時在注釋中已經建議的在XPath中使用translate稍短。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM