Eu direi o que sempre faço. Por favor, NUNCA use expressões regulares para analisar XML. São más notícias. O XML tem várias formatações diferentes, o que significa que o XML semanticamente idêntico corresponderá ou não a determinadas expressões regulares. Coisas simples, como quebra automática de linha, tags unários, etc.
Isso significa que você cria um código frágil, que um dia pode ser misteriosamente interrompido devido a uma alteração válida e ascendente do fluxo de dados.
Para analisar seu XML, sugiro usar perl
e o excelente XML::Twig
módulo.
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
use MIME::Base64;
#we take a "value" element, check it for an "encoding=base64" and if it is
#we rewrite the content and delete that attribute in the XML.
sub decode_value {
my ( $twig, $value ) = @_;
if ( $value->att('encoding')
and $value->att('encoding') eq "base64" )
{
my $decoded_text = decode_base64( $value->text );
if ( $decoded_text =~ m/[^\s\d\w\=\-\,\.]/ ) {
$decoded_text = "decoded";
}
$value->set_text($decoded_text);
$value -> del_att('encoding');
}
}
#twig handlers 'fires' a piece of code each time you hit a 'value' element.
#it passes this piece of code that chunk of XML to handle, which means
#you can do things like dynamic XML rewrites
#pretty print controls output XML rendering - there's a variety of options
#check the manpage.
my $twig = XML::Twig->new(
pretty_print => "indented",
twig_handlers => { 'value' => \&decode_value, }
);
$twig->parsefile('your_xml_file');
$twig->print;
Isso vai dar:
<directory-entries>
<entry dn="ads">
<attr name="memberof">
<value>CN=VPN-employee</value>
<value encoding="base64">hello world</value>
<value encoding="base64">decoded</value>
<value encoding="base64">decoded</value>
</attr>
</entry>
</directory-entries>
Você pode, alternativamente, transformar $decoded_text
assim:
$decoded_text =~ s/[^\s\d\w=,-. ]+/_/g;
( URI::Escape
module vale a pena dar uma olhada aqui também, já que 'porcentagem codifica' o estilo de URL de texto.)
O que daria em vez disso:
<value encoding="base64">CN=Floppy - _ _,OU=Device Control,OU=Groups,OU=_,DC=hq,DC=bc</value>
<value encoding="base64">CN=USB-_ - _ _,OU=Device Control,OU=Groups,OU=_,DC=hq,DC=bc</value>
Mas você também pode descobrir que usar Net::LDAP
faz o que você precisa.
#!/usr/bin/perl
use strict;
use warnings;
use Net::LDAP;
my $ldap = Net::LDAP->new('host');
my $result = $ldap->bind(
'CN=informatica,OU=Accounts for System Purposes,OU=System Accounts,DC=hq,DC=bc',
'password'
);
if ( $result->code ) { die "Error connecting to LDAP server"; }
my $ldap_search = $ldap->search(
base => 'DC=hq,DC=bc',
scope => 'subtree',
filter => '(&(objectClass=organizationalPerson)(CN=*))',
attrs => [ 'employeeID', 'memberOf' ],
);
foreach my $entry ( $ldap_search->entries ) {
print "dn:\t", $entry->dn(), "\n";
foreach my $attr ( $entry->attributes ) {
print "$attr:";
foreach my $value ( $entry->get_value($attr) ) {
next unless defined $value;
if ( $value =~ m/[^\s\d\w,-=+@\'.()]/ ) { $value = "binary_data" }
chomp($value);
print "\t$value\n";
}
}
}