1579 lines
53 KiB
Perl
1579 lines
53 KiB
Perl
# --
|
|
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
|
# --
|
|
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
|
# the enclosed file COPYING for license information (GPL). If you
|
|
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
|
# --
|
|
|
|
package Kernel::System::XML;
|
|
## nofilter(TidyAll::Plugin::OTRS::Perl::Require)
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Digest::MD5;
|
|
|
|
our @ObjectDependencies = (
|
|
'Kernel::System::Cache',
|
|
'Kernel::System::DB',
|
|
'Kernel::System::Encode',
|
|
'Kernel::System::Log',
|
|
);
|
|
|
|
=head1 NAME
|
|
|
|
Kernel::System::XML - xml lib
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
All xml related functions.
|
|
|
|
=head1 PUBLIC INTERFACE
|
|
|
|
=head2 new()
|
|
|
|
Don't use the constructor directly, use the ObjectManager instead:
|
|
|
|
my $XMLObject = $Kernel::OM->Get('Kernel::System::XML');
|
|
|
|
=cut
|
|
|
|
sub new {
|
|
my ( $Type, %Param ) = @_;
|
|
|
|
# allocate new hash for object
|
|
my $Self = {};
|
|
bless( $Self, $Type );
|
|
|
|
return $Self;
|
|
}
|
|
|
|
=head2 XMLHashAdd()
|
|
|
|
add an XMLHash to storage
|
|
|
|
my $Key = $XMLObject->XMLHashAdd(
|
|
Type => 'SomeType',
|
|
Key => '123',
|
|
XMLHash => \@XMLHash,
|
|
);
|
|
|
|
my $AutoKey = $XMLObject->XMLHashAdd(
|
|
Type => 'SomeType',
|
|
KeyAutoIncrement => 1,
|
|
XMLHash => \@XMLHash,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub XMLHashAdd {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for (qw(Type XMLHash)) {
|
|
if ( !$Param{$_} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $_!"
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( !$Param{Key} && !$Param{KeyAutoIncrement} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need Key or KeyAutoIncrement param!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
my %ValueHASH = $Self->XMLHash2D( XMLHash => $Param{XMLHash} );
|
|
if (%ValueHASH) {
|
|
if ( !$Param{Key} ) {
|
|
$Param{Key} = $Self->_XMLHashAddAutoIncrement(%Param);
|
|
}
|
|
if ( !$Param{Key} ) {
|
|
return;
|
|
}
|
|
$Self->XMLHashDelete(%Param);
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# create rand number
|
|
my $Rand = int( rand(1000000) );
|
|
my $TmpKey = "TMP-$Rand-$Param{Type}";
|
|
for my $Key ( sort keys %ValueHASH ) {
|
|
$DBObject->Do(
|
|
SQL =>
|
|
'INSERT INTO xml_storage (xml_type, xml_key, xml_content_key, xml_content_value) VALUES (?, ?, ?, ?)',
|
|
Bind => [ \$TmpKey, \$Param{Key}, \$Key, \$ValueHASH{$Key}, ],
|
|
);
|
|
}
|
|
|
|
# move new hash if insert is complete
|
|
$Self->XMLHashMove(
|
|
OldType => $TmpKey,
|
|
OldKey => $Param{Key},
|
|
NewType => $Param{Type},
|
|
NewKey => $Param{Key},
|
|
);
|
|
return $Param{Key};
|
|
}
|
|
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Got no %ValueHASH from XMLHash2D()',
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
=head2 XMLHashUpdate()
|
|
|
|
update an XMLHash to storage
|
|
|
|
$XMLHash[1]->{Name}->[1]->{Content} = 'Some Name';
|
|
|
|
$XMLObject->XMLHashUpdate(
|
|
Type => 'SomeType',
|
|
Key => '123',
|
|
XMLHash => \@XMLHash,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub XMLHashUpdate {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for (qw(Type Key XMLHash)) {
|
|
if ( !$Param{$_} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $_!"
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
return $Self->XMLHashAdd(%Param);
|
|
}
|
|
|
|
=head2 XMLHashGet()
|
|
|
|
get an XMLHash from the database
|
|
|
|
my @XMLHash = $XMLObject->XMLHashGet(
|
|
Type => 'SomeType',
|
|
Key => '123',
|
|
);
|
|
|
|
my @XMLHash = $XMLObject->XMLHashGet(
|
|
Type => 'SomeType',
|
|
Key => '123',
|
|
Cache => 0, # (optional) do not use cached data
|
|
);
|
|
|
|
=cut
|
|
|
|
sub XMLHashGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $Content = '';
|
|
my @XMLHash;
|
|
|
|
# check needed stuff
|
|
for (qw(Type Key)) {
|
|
if ( !$Param{$_} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $_!"
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
if ( !defined $Param{Cache} ) {
|
|
$Param{Cache} = 1;
|
|
}
|
|
|
|
# get cache object
|
|
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
|
|
|
|
# check cache
|
|
if ( $Param{Cache} ) {
|
|
my $Cache = $CacheObject->Get(
|
|
Type => 'XML',
|
|
Key => "$Param{Type}-$Param{Key}",
|
|
|
|
# Don't store complex structure in memory as it will be modified later.
|
|
CacheInMemory => 0,
|
|
);
|
|
return @{$Cache} if $Cache;
|
|
}
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# sql
|
|
return if !$DBObject->Prepare(
|
|
SQL => 'SELECT xml_content_key, xml_content_value '
|
|
. ' FROM xml_storage WHERE xml_type = ? AND xml_key = ?',
|
|
Bind => [ \$Param{Type}, \$Param{Key} ],
|
|
|
|
);
|
|
while ( my @Data = $DBObject->FetchrowArray() ) {
|
|
if ( defined $Data[1] ) {
|
|
$Data[1] =~ s/\\/\\\\/g;
|
|
$Data[1] =~ s/'/\\'/g;
|
|
}
|
|
else {
|
|
$Data[1] = '';
|
|
}
|
|
$Content .= '$XMLHash' . $Data[0] . " = '$Data[1]';\n 1;\n";
|
|
}
|
|
if ( $Content && !eval $Content ) { ## no critic
|
|
print STDERR "ERROR: XML.pm $@\n";
|
|
}
|
|
|
|
# set cache
|
|
if ( $Param{Cache} && $Content ) {
|
|
$CacheObject->Set(
|
|
Type => 'XML',
|
|
Key => "$Param{Type}-$Param{Key}",
|
|
Value => \@XMLHash,
|
|
TTL => 24 * 60 * 60,
|
|
|
|
# Don't store complex structure in memory as it will be modified later.
|
|
CacheInMemory => 0,
|
|
);
|
|
}
|
|
|
|
return @XMLHash;
|
|
}
|
|
|
|
=head2 XMLHashDelete()
|
|
|
|
delete an XMLHash from the database
|
|
|
|
$XMLObject->XMLHashDelete(
|
|
Type => 'SomeType',
|
|
Key => '123',
|
|
);
|
|
|
|
=cut
|
|
|
|
sub XMLHashDelete {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for (qw(Type Key)) {
|
|
if ( !defined $Param{$_} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $_!"
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# remove cache
|
|
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
|
|
Type => 'XML',
|
|
Key => "$Param{Type}-$Param{Key}",
|
|
);
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
return if !$DBObject->Do(
|
|
SQL => 'DELETE FROM xml_storage WHERE xml_type = ? AND xml_key = ?',
|
|
Bind => [ \$Param{Type}, \$Param{Key} ],
|
|
);
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 XMLHashMove()
|
|
|
|
move an XMLHash from one type or/and key to another
|
|
|
|
$XMLObject->XMLHashMove(
|
|
OldType => 'SomeType',
|
|
OldKey => '123',
|
|
NewType => 'NewType',
|
|
NewKey => '321',
|
|
);
|
|
|
|
=cut
|
|
|
|
sub XMLHashMove {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for (qw(OldType OldKey NewType NewKey)) {
|
|
if ( !$Param{$_} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $_!"
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# get cache object
|
|
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
|
|
|
|
# remove cache
|
|
$CacheObject->Delete(
|
|
Type => 'XML',
|
|
Key => "$Param{OldType}-$Param{OldKey}",
|
|
);
|
|
$CacheObject->Delete(
|
|
Type => 'XML',
|
|
Key => "$Param{NewType}-$Param{NewKey}",
|
|
);
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
# delete existing xml hash
|
|
$DBObject->Do(
|
|
SQL => 'DELETE FROM xml_storage WHERE xml_type = ? AND xml_key = ?',
|
|
Bind => [ \$Param{NewType}, \$Param{NewKey} ],
|
|
);
|
|
|
|
# update xml hash
|
|
return if !$DBObject->Do(
|
|
SQL => 'UPDATE xml_storage SET xml_type = ?, xml_key = ? '
|
|
. 'WHERE xml_type = ? AND xml_key = ?',
|
|
Bind => [ \$Param{NewType}, \$Param{NewKey}, \$Param{OldType}, \$Param{OldKey} ],
|
|
);
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 XMLHashSearch()
|
|
|
|
Search an XMLHash in the database.
|
|
|
|
my @Keys = $XMLObject->XMLHashSearch(
|
|
Type => 'SomeType',
|
|
What => [
|
|
# each array element is a and condition
|
|
{
|
|
# or condition in hash
|
|
"[%]{'ElementA'}[%]{'ElementB'}[%]{'Content'}" => '%contentA%',
|
|
"[%]{'ElementA'}[%]{'ElementC'}[%]{'Content'}" => '%contentA%',
|
|
},
|
|
{
|
|
"[%]{'ElementA'}[%]{'ElementB'}[%]{'Content'}" => '%contentB%',
|
|
"[%]{'ElementA'}[%]{'ElementC'}[%]{'Content'}" => '%contentB%',
|
|
},
|
|
{
|
|
# use array reference if different content with same key was searched
|
|
"[%]{'ElementA'}[%]{'ElementB'}[%]{'Content'}" => ['%contentC%', '%contentD%', '%contentE%'],
|
|
"[%]{'ElementA'}[%]{'ElementC'}[%]{'Content'}" => ['%contentC%', '%contentD%', '%contentE%'],
|
|
},
|
|
],
|
|
);
|
|
|
|
=cut
|
|
|
|
sub XMLHashSearch {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{Type} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need Type!'
|
|
);
|
|
return;
|
|
}
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
return if !$DBObject->Prepare(
|
|
SQL => 'SELECT DISTINCT(xml_key) FROM xml_storage WHERE xml_type = ?',
|
|
Bind => [ \$Param{Type} ],
|
|
);
|
|
|
|
# the keys of this hash will be returned
|
|
my %Hash;
|
|
|
|
# initially all keys with the correct type are possible
|
|
while ( my @Data = $DBObject->FetchrowArray() ) {
|
|
$Hash{ $Data[0] } = 1;
|
|
}
|
|
|
|
if ( $Param{What} && ref $Param{What} eq 'ARRAY' ) {
|
|
|
|
# get like escape string needed for some databases (e.g. oracle)
|
|
my $LikeEscapeString = $DBObject->GetDatabaseFunction('LikeEscapeString');
|
|
|
|
# the array elements are 'and' combined
|
|
for my $And ( @{ $Param{What} } ) {
|
|
|
|
# the key/value pairs are 'or' combined
|
|
my @OrConditions;
|
|
for my $Key ( sort keys %{$And} ) {
|
|
my $Value = $DBObject->Quote( $And->{$Key} );
|
|
$Key = $DBObject->Quote( $Key, 'Like' );
|
|
if ( $Value && ref $Value eq 'ARRAY' ) {
|
|
|
|
# when an array of possible values is given,
|
|
# we use 'LIKE'-conditions and combine them with 'OR'
|
|
for my $Element ( @{$Value} ) {
|
|
$Element = $DBObject->Quote( $Element, 'Like' );
|
|
push @OrConditions,
|
|
" (xml_content_key LIKE '$Key' $LikeEscapeString "
|
|
. "AND xml_content_value LIKE '$Element' $LikeEscapeString)";
|
|
}
|
|
}
|
|
else {
|
|
|
|
# when a single possible value is given,
|
|
# we use a 'LIKE'-condition
|
|
$Value = $DBObject->Quote( $Value, 'Like' );
|
|
push @OrConditions,
|
|
" (xml_content_key LIKE '$Key' $LikeEscapeString "
|
|
. "AND xml_content_value LIKE '$Value' $LikeEscapeString )";
|
|
}
|
|
}
|
|
|
|
# assemble the SQL
|
|
my $SQL = 'SELECT DISTINCT(xml_key) FROM xml_storage WHERE xml_type = ? ';
|
|
if (@OrConditions) {
|
|
$SQL .= 'AND ( ' . join( ' OR ', @OrConditions ) . ' ) ';
|
|
}
|
|
|
|
# execute
|
|
$DBObject->Prepare(
|
|
SQL => $SQL,
|
|
Bind => [ \$Param{Type} ],
|
|
);
|
|
|
|
# intersection between the current key set, and the keys from the last 'SELECT'
|
|
# only the keys which are in all results survive
|
|
my %HashNew;
|
|
while ( my @Data = $DBObject->FetchrowArray() ) {
|
|
if ( $Hash{ $Data[0] } ) {
|
|
$HashNew{ $Data[0] } = 1;
|
|
}
|
|
}
|
|
%Hash = %HashNew;
|
|
}
|
|
}
|
|
|
|
my @Keys = keys %Hash;
|
|
|
|
return @Keys;
|
|
}
|
|
|
|
=head2 XMLHashList()
|
|
|
|
generate a list of XMLHashes in the database
|
|
|
|
my @Keys = $XMLObject->XMLHashList(
|
|
Type => 'SomeType',
|
|
);
|
|
|
|
=cut
|
|
|
|
sub XMLHashList {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{Type} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need Type!'
|
|
);
|
|
return;
|
|
}
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
return if !$DBObject->Prepare(
|
|
SQL => 'SELECT distinct(xml_key) FROM xml_storage WHERE xml_type = ?',
|
|
Bind => [ \$Param{Type} ],
|
|
);
|
|
|
|
my @Keys;
|
|
while ( my @Data = $DBObject->FetchrowArray() ) {
|
|
push @Keys, $Data[0];
|
|
}
|
|
|
|
return @Keys;
|
|
}
|
|
|
|
=head2 XMLHash2XML()
|
|
|
|
generate an XML string from an XMLHash
|
|
|
|
my $XMLString = $XMLObject->XMLHash2XML(@XMLHash);
|
|
|
|
=cut
|
|
|
|
sub XMLHash2XML {
|
|
my ( $Self, @XMLHash ) = @_;
|
|
|
|
my $Output = '<?xml version="1.0" encoding="utf-8"?>' . "\n";
|
|
|
|
$Self->{XMLHash2XMLLayer} = 0;
|
|
for my $Key (@XMLHash) {
|
|
$Output .= $Self->_ElementBuild( %{$Key} );
|
|
}
|
|
|
|
return $Output;
|
|
}
|
|
|
|
=head2 XMLParse2XMLHash()
|
|
|
|
parse an XML file and return an XMLHash structure
|
|
|
|
my @XMLHash = $XMLObject->XMLParse2XMLHash( String => $FileString );
|
|
|
|
XML:
|
|
====
|
|
<Contact role="admin" type="organization">
|
|
<Name type="long">Example Inc.</Name>
|
|
<Email type="primary">info@exampe.com<Domain>1234.com</Domain></Email>
|
|
<Email type="secondary">sales@example.com</Email>
|
|
<Telephone country="germany">+49-999-99999</Telephone>
|
|
</Contact>
|
|
|
|
ARRAY:
|
|
======
|
|
@XMLHash = (
|
|
undef,
|
|
{
|
|
Contact => [
|
|
undef,
|
|
{
|
|
role => 'admin',
|
|
type => 'organization',
|
|
Name => [
|
|
undef,
|
|
{
|
|
Content => 'Example Inc.',
|
|
type => 'long',
|
|
},
|
|
],
|
|
Email => [
|
|
undef,
|
|
{
|
|
type => 'primary',
|
|
Content => 'info@exampe.com',
|
|
Domain => [
|
|
undef,
|
|
{
|
|
Content => '1234.com',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
type => 'secondary',
|
|
Content => 'sales@exampe.com',
|
|
},
|
|
],
|
|
Telephone => [
|
|
undef,
|
|
{
|
|
country => 'germany',
|
|
Content => '+49-999-99999',
|
|
},
|
|
],
|
|
}
|
|
],
|
|
}
|
|
);
|
|
|
|
$XMLHash[1]{Contact}[1]{TagKey} = "[1]{'Contact'}[1]";
|
|
$XMLHash[1]{Contact}[1]{role} = "admin";
|
|
$XMLHash[1]{Contact}[1]{type} = "organization";
|
|
$XMLHash[1]{Contact}[1]{Name}[1]{TagKey} = "[1]{'Contact'}[1]{'Name'}[1]";
|
|
$XMLHash[1]{Contact}[1]{Name}[1]{Content} = "Example Inc.";
|
|
$XMLHash[1]{Contact}[1]{Name}[1]{type} = "long";
|
|
$XMLHash[1]{Contact}[1]{Email}[1]{TagKey} = "[1]{'Contact'}[1]{'Email'}[1]";
|
|
$XMLHash[1]{Contact}[1]{Email}[1]{Content} = "info\@exampe.com";
|
|
$XMLHash[1]{Contact}[1]{Email}[1]{Domain}[1]{TagKey} = "[1]{'Contact'}[1]{'Email'}[1]{'Domain'}[1]";
|
|
$XMLHash[1]{Contact}[1]{Email}[1]{Domain}[1]{Content} = "1234.com";
|
|
$XMLHash[1]{Contact}[1]{Email}[2]{TagKey} = "[1]{'Contact'}[1]{'Email'}[2]";
|
|
$XMLHash[1]{Contact}[1]{Email}[2]{type} = "secondary";
|
|
$XMLHash[1]{Contact}[1]{Email}[2]{Content} = "sales\@exampe.com";
|
|
|
|
=cut
|
|
|
|
sub XMLParse2XMLHash {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my @XMLStructure = $Self->XMLParse(%Param);
|
|
return () if !@XMLStructure;
|
|
|
|
my @XMLHash = ( undef, $Self->XMLStructure2XMLHash( XMLStructure => \@XMLStructure ) );
|
|
return @XMLHash;
|
|
|
|
}
|
|
|
|
=head2 XMLHash2D()
|
|
|
|
returns a simple hash with tag keys as keys and the values of C<XMLHash> as values.
|
|
As a side effect the data structure C<XMLHash> is enriched with tag keys.
|
|
|
|
my %Hash = $XMLObject->XMLHash2D( XMLHash => \@XMLHash );
|
|
|
|
For example:
|
|
|
|
$Hash{"[1]{'Planet'}[1]{'Content'}"'} = 'Sun';
|
|
|
|
=cut
|
|
|
|
sub XMLHash2D {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !defined $Param{XMLHash} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'XMLHash not defined!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
$Self->{XMLLevel} = 0;
|
|
$Self->{XMLTagCount} = 0;
|
|
$Self->{XMLHash} = {};
|
|
$Self->{XMLHashReturn} = 1;
|
|
undef $Self->{XMLLevelTag};
|
|
undef $Self->{XMLLevelCount};
|
|
|
|
my $Count = 0;
|
|
for my $Item ( @{ $Param{XMLHash} } ) {
|
|
if ( ref $Item eq 'HASH' ) {
|
|
for ( sort keys %{$Item} ) {
|
|
$Self->_XMLHash2D(
|
|
Key => $Item->{Tag},
|
|
Item => $Item,
|
|
Counter => $Count
|
|
);
|
|
}
|
|
}
|
|
$Count++;
|
|
}
|
|
$Self->{XMLHashReturn} = 0;
|
|
|
|
return %{ $Self->{XMLHash} };
|
|
}
|
|
|
|
=head2 XMLStructure2XMLHash()
|
|
|
|
get an @XMLHash from a @XMLStructure with current TagKey param
|
|
|
|
my @XMLHash = $XMLObject->XMLStructure2XMLHash( XMLStructure => \@XMLStructure );
|
|
|
|
=cut
|
|
|
|
sub XMLStructure2XMLHash {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !defined $Param{XMLStructure} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'XMLStructure not defined!'
|
|
);
|
|
return;
|
|
}
|
|
|
|
$Self->{Tll} = 0;
|
|
$Self->{XMLTagCount} = 0;
|
|
$Self->{XMLHash2} = {};
|
|
$Self->{XMLHashReturn} = 1;
|
|
undef $Self->{XMLLevelTag};
|
|
undef $Self->{XMLLevelCount};
|
|
|
|
for my $Item ( @{ $Param{XMLStructure} } ) {
|
|
if ( ref $Item eq 'HASH' ) {
|
|
$Self->_XMLStructure2XMLHash(
|
|
Key => $Item->{Tag},
|
|
Item => $Item,
|
|
Type => 'ARRAY'
|
|
);
|
|
}
|
|
}
|
|
$Self->{XMLHashReturn} = 0;
|
|
|
|
return ( \%{ $Self->{XMLHash2} } );
|
|
}
|
|
|
|
=head2 XMLParse()
|
|
|
|
parse an XML file
|
|
|
|
my @XMLStructure = $XMLObject->XMLParse( String => $FileString );
|
|
|
|
my @XMLStructure = $XMLObject->XMLParse( String => \$FileStringScalar );
|
|
|
|
=cut
|
|
|
|
sub XMLParse {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !defined $Param{String} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'String not defined!'
|
|
);
|
|
return;
|
|
}
|
|
|
|
# check input type
|
|
if ( ref $Param{String} ) {
|
|
$Param{String} = ${ $Param{String} };
|
|
}
|
|
|
|
# get encode object
|
|
my $EncodeObject = $Kernel::OM->Get('Kernel::System::Encode');
|
|
|
|
# create checksum
|
|
my $CookedString = $Param{String};
|
|
$EncodeObject->EncodeOutput( \$CookedString );
|
|
my $MD5Object = Digest::MD5->new();
|
|
$MD5Object->add($CookedString);
|
|
my $Checksum = $MD5Object->hexdigest();
|
|
|
|
# get cache object
|
|
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
|
|
|
|
# check cache
|
|
if ($Checksum) {
|
|
|
|
# set CacheInMemory to 0 to prevent modification of the cache from outside
|
|
# See bug#[12761](https://bugs.otrs.org/show_bug.cgi?id=12761) for further details
|
|
my $Cache = $CacheObject->Get(
|
|
Type => 'XMLParse',
|
|
Key => $Checksum,
|
|
CacheInMemory => 0,
|
|
);
|
|
|
|
return @{$Cache} if $Cache;
|
|
}
|
|
|
|
# cleanup global vars
|
|
undef $Self->{XMLARRAY};
|
|
$Self->{XMLLevel} = 0;
|
|
$Self->{XMLTagCount} = 0;
|
|
undef $Self->{XMLLevelTag};
|
|
undef $Self->{XMLLevelCount};
|
|
|
|
# convert string
|
|
if ( $Param{String} =~ /(<.+?>)/ ) {
|
|
if ( $1 !~ /(utf-8|utf8)/i && $1 =~ /encoding=('|")(.+?)('|")/i ) {
|
|
my $SourceCharset = $2;
|
|
$Param{String} =~ s/$SourceCharset/utf-8/i;
|
|
$Param{String} = $EncodeObject->Convert(
|
|
Text => $Param{String},
|
|
From => $SourceCharset,
|
|
To => 'utf-8',
|
|
Force => 1,
|
|
);
|
|
}
|
|
}
|
|
|
|
# load parse package and parse
|
|
my $UseFallback = 1;
|
|
|
|
if ( eval 'require XML::Parser' ) { ## no critic
|
|
my $Parser = XML::Parser->new(
|
|
Handlers => {
|
|
Start => sub { $Self->_HS(@_); },
|
|
End => sub { $Self->_ES(@_); },
|
|
Char => sub { $Self->_CS(@_); },
|
|
ExternEnt => sub { return '' }, # suppress loading of external entities
|
|
},
|
|
);
|
|
|
|
# get sourcename now to avoid a possible race condition where
|
|
# $@ could get altered after a failing eval!
|
|
my $Sourcename = $Param{Sourcename} ? "\n\n($Param{Sourcename})" : '';
|
|
|
|
if ( eval { $Parser->parse( $Param{String} ) } ) {
|
|
$UseFallback = 0;
|
|
|
|
# remember, XML::Parser is managing e. g. & by it self
|
|
$Self->{XMLQuote} = 0;
|
|
}
|
|
else {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "C-Parser: $@!$Sourcename"
|
|
);
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message =>
|
|
"XML::Parser had errors, falling back to XML::Parser::Lite. Offending XML was: $Param{String}",
|
|
);
|
|
}
|
|
}
|
|
|
|
if ($UseFallback) {
|
|
require XML::Parser::Lite; ## no critic
|
|
|
|
my $Parser = XML::Parser::Lite->new(
|
|
Handlers => {
|
|
Start => sub { $Self->_HS(@_); },
|
|
End => sub { $Self->_ES(@_); },
|
|
Char => sub { $Self->_CS(@_); },
|
|
ExternEnt => sub { return '' }, # suppress loading of external entities
|
|
},
|
|
);
|
|
$Parser->parse( $Param{String} );
|
|
|
|
# remember, XML::Parser::Lite is managing e. g. & NOT by it self
|
|
$Self->{XMLQuote} = 1;
|
|
}
|
|
|
|
# quote
|
|
for my $XMLElement ( @{ $Self->{XMLARRAY} } ) {
|
|
$Self->_Decode($XMLElement);
|
|
}
|
|
|
|
# set cache
|
|
if ($Checksum) {
|
|
|
|
# set CacheInMemory to 0 to prevent modification of the cache from outside
|
|
# See bug#[12761](https://bugs.otrs.org/show_bug.cgi?id=12761) for further details
|
|
$CacheObject->Set(
|
|
Type => 'XMLParse',
|
|
Key => $Checksum,
|
|
Value => $Self->{XMLARRAY},
|
|
TTL => 30 * 24 * 60 * 60,
|
|
CacheInMemory => 0,
|
|
);
|
|
}
|
|
|
|
return @{ $Self->{XMLARRAY} };
|
|
}
|
|
|
|
=begin Internal:
|
|
|
|
=head2 _XMLHashAddAutoIncrement()
|
|
|
|
Generate a new integer key.
|
|
All keys for that type must be integers.
|
|
|
|
my $Key = $XMLObject->_XMLHashAddAutoIncrement(
|
|
Type => 'SomeType',
|
|
KeyAutoIncrement => 1,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub _XMLHashAddAutoIncrement {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $KeyAutoIncrement = 0;
|
|
my @KeysExists;
|
|
|
|
# check needed stuff
|
|
for (qw(Type KeyAutoIncrement)) {
|
|
if ( !$Param{$_} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $_!"
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# get database object
|
|
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
|
|
|
return if !$DBObject->Prepare(
|
|
SQL => 'SELECT DISTINCT(xml_key) FROM xml_storage WHERE xml_type = ?',
|
|
Bind => [ \$Param{Type} ],
|
|
);
|
|
|
|
while ( my @Data = $DBObject->FetchrowArray() ) {
|
|
if ( $Data[0] ) {
|
|
push @KeysExists, $Data[0];
|
|
}
|
|
}
|
|
|
|
for my $Key (@KeysExists) {
|
|
if ( $Key !~ /^\d{1,99}$/ ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "No KeyAutoIncrement possible, no int key exists ($Key)!",
|
|
);
|
|
return;
|
|
}
|
|
if ( $Key > $KeyAutoIncrement ) {
|
|
$KeyAutoIncrement = $Key;
|
|
}
|
|
}
|
|
|
|
$KeyAutoIncrement++;
|
|
return $KeyAutoIncrement;
|
|
}
|
|
|
|
sub _ElementBuild {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my @Tag;
|
|
my @Sub;
|
|
my $Output = '';
|
|
|
|
if ( $Param{Key} ) {
|
|
$Self->{XMLHash2XMLLayer}++;
|
|
$Output .= "<$Param{Key}";
|
|
}
|
|
|
|
for ( sort keys %Param ) {
|
|
if ( ref $Param{$_} eq 'ARRAY' ) {
|
|
push @Tag, $_;
|
|
push @Sub, $Param{$_};
|
|
}
|
|
elsif ( $_ ne 'Content' && $_ ne 'Key' && $_ !~ /^Tag/ ) {
|
|
if ( defined $Param{$_} ) {
|
|
$Param{$_} =~ s/&/&/g;
|
|
$Param{$_} =~ s/</</g;
|
|
$Param{$_} =~ s/>/>/g;
|
|
$Param{$_} =~ s/"/"/g;
|
|
}
|
|
$Output .= " $_=\"$Param{$_}\"";
|
|
}
|
|
}
|
|
if ( $Param{Key} ) {
|
|
$Output .= '>';
|
|
}
|
|
if ( defined $Param{Content} ) {
|
|
|
|
# encode
|
|
$Param{Content} =~ s/&/&/g;
|
|
$Param{Content} =~ s/</</g;
|
|
$Param{Content} =~ s/>/>/g;
|
|
$Param{Content} =~ s/"/"/g;
|
|
$Output .= $Param{Content};
|
|
}
|
|
else {
|
|
$Output .= "\n";
|
|
}
|
|
for ( 0 .. $#Sub ) {
|
|
for my $K ( @{ $Sub[$_] } ) {
|
|
if ( defined $K ) {
|
|
$Output .= $Self->_ElementBuild(
|
|
%{$K},
|
|
Key => $Tag[$_],
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( $Param{Key} ) {
|
|
$Output .= "</$Param{Key}>\n";
|
|
$Self->{XMLHash2XMLLayer} = $Self->{XMLHash2XMLLayer} - 1;
|
|
}
|
|
|
|
return $Output;
|
|
}
|
|
|
|
sub _XMLHash2D {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
if ( !defined $Param{Item} ) {
|
|
return '';
|
|
}
|
|
elsif ( ref $Param{Item} eq 'HASH' ) {
|
|
$Self->{XMLLevel}++;
|
|
$Self->{XMLTagCount}++;
|
|
$Self->{XMLLevelTag}->{ $Self->{XMLLevel} } = $Param{Key};
|
|
if ( $Self->{Tll} && $Self->{Tll} > $Self->{XMLLevel} ) {
|
|
for ( ( $Self->{XMLLevel} + 1 ) .. 30 ) {
|
|
undef $Self->{XMLLevelCount}->{$_}; #->{$Element} = 0;
|
|
}
|
|
}
|
|
$Self->{XMLLevelCount}->{ $Self->{XMLLevel} }->{ $Param{Key} || '' }++;
|
|
|
|
# remember old level
|
|
$Self->{Tll} = $Self->{XMLLevel};
|
|
|
|
my $Key = "[$Param{Counter}]";
|
|
for ( 2 .. ( $Self->{XMLLevel} ) ) {
|
|
$Key .= "{'$Self->{XMLLevelTag}->{$_}'}";
|
|
$Key .= "[" . $Self->{XMLLevelCount}->{$_}->{ $Self->{XMLLevelTag}->{$_} } . "]";
|
|
}
|
|
|
|
# add tag key to the passed in data structure
|
|
$Param{Item}->{TagKey} = $Key;
|
|
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( defined $Param{Item}->{$_} && ref $Param{Item}->{$_} ne 'ARRAY' ) {
|
|
$Self->{XMLHash}->{ $Key . "{'$_'}" } = $Param{Item}->{$_};
|
|
}
|
|
$Self->_XMLHash2D(
|
|
Key => $_,
|
|
Item => $Param{Item}->{$_},
|
|
Counter => $Param{Counter}
|
|
);
|
|
}
|
|
$Self->{XMLLevel} = $Self->{XMLLevel} - 1;
|
|
}
|
|
elsif ( ref $Param{Item} eq 'ARRAY' ) {
|
|
for ( @{ $Param{Item} } ) {
|
|
$Self->_XMLHash2D(
|
|
Key => $Param{Key},
|
|
Item => $_,
|
|
Counter => $Param{Counter}
|
|
);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub _XMLStructure2XMLHash {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $Output = '';
|
|
|
|
if ( !defined $Param{Item} ) {
|
|
return;
|
|
}
|
|
elsif ( ref $Param{Item} eq 'HASH' ) {
|
|
if ( $Param{Item}->{TagType} eq 'End' ) {
|
|
return '';
|
|
}
|
|
$Self->{XMLTagCount}++;
|
|
$Self->{XMLLevelTag}->{ $Param{Item}->{TagLevel} } = $Param{Key};
|
|
if ( $Self->{Tll} && $Self->{Tll} > $Param{Item}->{TagLevel} ) {
|
|
for ( ( $Param{Item}->{TagLevel} + 1 ) .. 30 ) {
|
|
undef $Self->{XMLLevelCount}->{$_};
|
|
}
|
|
}
|
|
$Self->{XMLLevelCount}->{ $Param{Item}->{TagLevel} }->{ $Param{Key} }++;
|
|
|
|
# remember old level
|
|
$Self->{Tll} = $Param{Item}->{TagLevel};
|
|
|
|
if ( $Param{Item}->{TagLevel} == 1 ) {
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( !defined $Param{Item}->{$_} ) {
|
|
$Param{Item}->{$_} = '';
|
|
}
|
|
if ( $_ !~ /^Tag/ ) {
|
|
$Self->{XMLHash2}->{ $Self->{XMLLevelTag}->{1} }
|
|
->[ $Self->{XMLLevelCount}->{1}->{ $Self->{XMLLevelTag}->{1} } ]->{$_} = $Param{Item}->{$_};
|
|
}
|
|
}
|
|
}
|
|
elsif ( $Param{Item}->{TagLevel} == 2 ) {
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( !defined $Param{Item}->{$_} ) {
|
|
$Param{Item}->{$_} = '';
|
|
}
|
|
if ( $_ !~ /^Tag/ ) {
|
|
$Self->{XMLHash2}->{ $Self->{XMLLevelTag}->{1} }
|
|
->[ $Self->{XMLLevelCount}->{1}->{ $Self->{XMLLevelTag}->{1} } ]
|
|
->{ $Self->{XMLLevelTag}->{2} }
|
|
->[ $Self->{XMLLevelCount}->{2}->{ $Self->{XMLLevelTag}->{2} } ]->{$_} = $Param{Item}->{$_};
|
|
}
|
|
}
|
|
}
|
|
elsif ( $Param{Item}->{TagLevel} == 3 ) {
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( !defined $Param{Item}->{$_} ) {
|
|
$Param{Item}->{$_} = '';
|
|
}
|
|
if ( $_ !~ /^Tag/ ) {
|
|
$Self->{XMLHash2}->{ $Self->{XMLLevelTag}->{1} }
|
|
->[ $Self->{XMLLevelCount}->{1}->{ $Self->{XMLLevelTag}->{1} } ]
|
|
->{ $Self->{XMLLevelTag}->{2} }
|
|
->[ $Self->{XMLLevelCount}->{2}->{ $Self->{XMLLevelTag}->{2} } ]
|
|
->{ $Self->{XMLLevelTag}->{3} }
|
|
->[ $Self->{XMLLevelCount}->{3}->{ $Self->{XMLLevelTag}->{3} } ]->{$_} = $Param{Item}->{$_};
|
|
}
|
|
}
|
|
}
|
|
elsif ( $Param{Item}->{TagLevel} == 4 ) {
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( !defined $Param{Item}->{$_} ) {
|
|
$Param{Item}->{$_} = '';
|
|
}
|
|
if ( $_ !~ /^Tag/ ) {
|
|
$Self->{XMLHash2}->{ $Self->{XMLLevelTag}->{1} }
|
|
->[ $Self->{XMLLevelCount}->{1}->{ $Self->{XMLLevelTag}->{1} } ]
|
|
->{ $Self->{XMLLevelTag}->{2} }
|
|
->[ $Self->{XMLLevelCount}->{2}->{ $Self->{XMLLevelTag}->{2} } ]
|
|
->{ $Self->{XMLLevelTag}->{3} }
|
|
->[ $Self->{XMLLevelCount}->{3}->{ $Self->{XMLLevelTag}->{3} } ]
|
|
->{ $Self->{XMLLevelTag}->{4} }
|
|
->[ $Self->{XMLLevelCount}->{4}->{ $Self->{XMLLevelTag}->{4} } ]->{$_} = $Param{Item}->{$_};
|
|
}
|
|
}
|
|
}
|
|
elsif ( $Param{Item}->{TagLevel} == 5 ) {
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( !defined $Param{Item}->{$_} ) {
|
|
$Param{Item}->{$_} = '';
|
|
}
|
|
if ( $_ !~ /^Tag/ ) {
|
|
$Self->{XMLHash2}->{ $Self->{XMLLevelTag}->{1} }
|
|
->[ $Self->{XMLLevelCount}->{1}->{ $Self->{XMLLevelTag}->{1} } ]
|
|
->{ $Self->{XMLLevelTag}->{2} }
|
|
->[ $Self->{XMLLevelCount}->{2}->{ $Self->{XMLLevelTag}->{2} } ]
|
|
->{ $Self->{XMLLevelTag}->{3} }
|
|
->[ $Self->{XMLLevelCount}->{3}->{ $Self->{XMLLevelTag}->{3} } ]
|
|
->{ $Self->{XMLLevelTag}->{4} }
|
|
->[ $Self->{XMLLevelCount}->{4}->{ $Self->{XMLLevelTag}->{4} } ]
|
|
->{ $Self->{XMLLevelTag}->{5} }
|
|
->[ $Self->{XMLLevelCount}->{5}->{ $Self->{XMLLevelTag}->{5} } ]->{$_} = $Param{Item}->{$_};
|
|
}
|
|
}
|
|
}
|
|
elsif ( $Param{Item}->{TagLevel} == 6 ) {
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( !defined $Param{Item}->{$_} ) {
|
|
$Param{Item}->{$_} = '';
|
|
}
|
|
if ( $_ !~ /^Tag/ ) {
|
|
$Self->{XMLHash2}->{ $Self->{XMLLevelTag}->{1} }
|
|
->[ $Self->{XMLLevelCount}->{1}->{ $Self->{XMLLevelTag}->{1} } ]
|
|
->{ $Self->{XMLLevelTag}->{2} }
|
|
->[ $Self->{XMLLevelCount}->{2}->{ $Self->{XMLLevelTag}->{2} } ]
|
|
->{ $Self->{XMLLevelTag}->{3} }
|
|
->[ $Self->{XMLLevelCount}->{3}->{ $Self->{XMLLevelTag}->{3} } ]
|
|
->{ $Self->{XMLLevelTag}->{4} }
|
|
->[ $Self->{XMLLevelCount}->{4}->{ $Self->{XMLLevelTag}->{4} } ]
|
|
->{ $Self->{XMLLevelTag}->{5} }
|
|
->[ $Self->{XMLLevelCount}->{5}->{ $Self->{XMLLevelTag}->{5} } ]
|
|
->{ $Self->{XMLLevelTag}->{6} }
|
|
->[ $Self->{XMLLevelCount}->{6}->{ $Self->{XMLLevelTag}->{6} } ]->{$_} = $Param{Item}->{$_};
|
|
}
|
|
}
|
|
}
|
|
elsif ( $Param{Item}->{TagLevel} == 7 ) {
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( !defined $Param{Item}->{$_} ) {
|
|
$Param{Item}->{$_} = '';
|
|
}
|
|
if ( $_ !~ /^Tag/ ) {
|
|
$Self->{XMLHash2}->{ $Self->{XMLLevelTag}->{1} }
|
|
->[ $Self->{XMLLevelCount}->{1}->{ $Self->{XMLLevelTag}->{1} } ]
|
|
->{ $Self->{XMLLevelTag}->{2} }
|
|
->[ $Self->{XMLLevelCount}->{2}->{ $Self->{XMLLevelTag}->{2} } ]
|
|
->{ $Self->{XMLLevelTag}->{3} }
|
|
->[ $Self->{XMLLevelCount}->{3}->{ $Self->{XMLLevelTag}->{3} } ]
|
|
->{ $Self->{XMLLevelTag}->{4} }
|
|
->[ $Self->{XMLLevelCount}->{4}->{ $Self->{XMLLevelTag}->{4} } ]
|
|
->{ $Self->{XMLLevelTag}->{5} }
|
|
->[ $Self->{XMLLevelCount}->{5}->{ $Self->{XMLLevelTag}->{5} } ]
|
|
->{ $Self->{XMLLevelTag}->{6} }
|
|
->[ $Self->{XMLLevelCount}->{6}->{ $Self->{XMLLevelTag}->{6} } ]
|
|
->{ $Self->{XMLLevelTag}->{7} }
|
|
->[ $Self->{XMLLevelCount}->{7}->{ $Self->{XMLLevelTag}->{7} } ]->{$_} = $Param{Item}->{$_};
|
|
}
|
|
}
|
|
}
|
|
elsif ( $Param{Item}->{TagLevel} == 8 ) {
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( !defined $Param{Item}->{$_} ) {
|
|
$Param{Item}->{$_} = '';
|
|
}
|
|
if ( $_ !~ /^Tag/ ) {
|
|
$Self->{XMLHash2}->{ $Self->{XMLLevelTag}->{1} }
|
|
->[ $Self->{XMLLevelCount}->{1}->{ $Self->{XMLLevelTag}->{1} } ]
|
|
->{ $Self->{XMLLevelTag}->{2} }
|
|
->[ $Self->{XMLLevelCount}->{2}->{ $Self->{XMLLevelTag}->{2} } ]
|
|
->{ $Self->{XMLLevelTag}->{3} }
|
|
->[ $Self->{XMLLevelCount}->{3}->{ $Self->{XMLLevelTag}->{3} } ]
|
|
->{ $Self->{XMLLevelTag}->{4} }
|
|
->[ $Self->{XMLLevelCount}->{4}->{ $Self->{XMLLevelTag}->{4} } ]
|
|
->{ $Self->{XMLLevelTag}->{5} }
|
|
->[ $Self->{XMLLevelCount}->{5}->{ $Self->{XMLLevelTag}->{5} } ]
|
|
->{ $Self->{XMLLevelTag}->{6} }
|
|
->[ $Self->{XMLLevelCount}->{6}->{ $Self->{XMLLevelTag}->{6} } ]
|
|
->{ $Self->{XMLLevelTag}->{7} }
|
|
->[ $Self->{XMLLevelCount}->{7}->{ $Self->{XMLLevelTag}->{7} } ]
|
|
->{ $Self->{XMLLevelTag}->{8} }
|
|
->[ $Self->{XMLLevelCount}->{8}->{ $Self->{XMLLevelTag}->{8} } ]->{$_} = $Param{Item}->{$_};
|
|
}
|
|
}
|
|
}
|
|
elsif ( $Param{Item}->{TagLevel} == 9 ) {
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( !defined $Param{Item}->{$_} ) {
|
|
$Param{Item}->{$_} = '';
|
|
}
|
|
if ( $_ !~ /^Tag/ ) {
|
|
$Self->{XMLHash2}->{ $Self->{XMLLevelTag}->{1} }
|
|
->[ $Self->{XMLLevelCount}->{1}->{ $Self->{XMLLevelTag}->{1} } ]
|
|
->{ $Self->{XMLLevelTag}->{2} }
|
|
->[ $Self->{XMLLevelCount}->{2}->{ $Self->{XMLLevelTag}->{2} } ]
|
|
->{ $Self->{XMLLevelTag}->{3} }
|
|
->[ $Self->{XMLLevelCount}->{3}->{ $Self->{XMLLevelTag}->{3} } ]
|
|
->{ $Self->{XMLLevelTag}->{4} }
|
|
->[ $Self->{XMLLevelCount}->{4}->{ $Self->{XMLLevelTag}->{4} } ]
|
|
->{ $Self->{XMLLevelTag}->{5} }
|
|
->[ $Self->{XMLLevelCount}->{5}->{ $Self->{XMLLevelTag}->{5} } ]
|
|
->{ $Self->{XMLLevelTag}->{6} }
|
|
->[ $Self->{XMLLevelCount}->{6}->{ $Self->{XMLLevelTag}->{6} } ]
|
|
->{ $Self->{XMLLevelTag}->{7} }
|
|
->[ $Self->{XMLLevelCount}->{7}->{ $Self->{XMLLevelTag}->{7} } ]
|
|
->{ $Self->{XMLLevelTag}->{8} }
|
|
->[ $Self->{XMLLevelCount}->{8}->{ $Self->{XMLLevelTag}->{8} } ]
|
|
->{ $Self->{XMLLevelTag}->{9} }
|
|
->[ $Self->{XMLLevelCount}->{9}->{ $Self->{XMLLevelTag}->{9} } ]->{$_} = $Param{Item}->{$_};
|
|
}
|
|
}
|
|
}
|
|
elsif ( $Param{Item}->{TagLevel} == 10 ) {
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( !defined $Param{Item}->{$_} ) {
|
|
$Param{Item}->{$_} = '';
|
|
}
|
|
if ( $_ !~ /^Tag/ ) {
|
|
$Self->{XMLHash2}->{ $Self->{XMLLevelTag}->{1} }
|
|
->[ $Self->{XMLLevelCount}->{1}->{ $Self->{XMLLevelTag}->{1} } ]
|
|
->{ $Self->{XMLLevelTag}->{2} }
|
|
->[ $Self->{XMLLevelCount}->{2}->{ $Self->{XMLLevelTag}->{2} } ]
|
|
->{ $Self->{XMLLevelTag}->{3} }
|
|
->[ $Self->{XMLLevelCount}->{3}->{ $Self->{XMLLevelTag}->{3} } ]
|
|
->{ $Self->{XMLLevelTag}->{4} }
|
|
->[ $Self->{XMLLevelCount}->{4}->{ $Self->{XMLLevelTag}->{4} } ]
|
|
->{ $Self->{XMLLevelTag}->{5} }
|
|
->[ $Self->{XMLLevelCount}->{5}->{ $Self->{XMLLevelTag}->{5} } ]
|
|
->{ $Self->{XMLLevelTag}->{6} }
|
|
->[ $Self->{XMLLevelCount}->{6}->{ $Self->{XMLLevelTag}->{6} } ]
|
|
->{ $Self->{XMLLevelTag}->{7} }
|
|
->[ $Self->{XMLLevelCount}->{7}->{ $Self->{XMLLevelTag}->{7} } ]
|
|
->{ $Self->{XMLLevelTag}->{8} }
|
|
->[ $Self->{XMLLevelCount}->{8}->{ $Self->{XMLLevelTag}->{8} } ]
|
|
->{ $Self->{XMLLevelTag}->{9} }
|
|
->[ $Self->{XMLLevelCount}->{9}->{ $Self->{XMLLevelTag}->{9} } ]
|
|
->{ $Self->{XMLLevelTag}->{10} }
|
|
->[ $Self->{XMLLevelCount}->{10}->{ $Self->{XMLLevelTag}->{10} } ]->{$_} = $Param{Item}->{$_};
|
|
}
|
|
}
|
|
}
|
|
elsif ( $Param{Item}->{TagLevel} == 11 ) {
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( !defined $Param{Item}->{$_} ) {
|
|
$Param{Item}->{$_} = '';
|
|
}
|
|
if ( $_ !~ /^Tag/ ) {
|
|
$Self->{XMLHash2}->{ $Self->{XMLLevelTag}->{1} }
|
|
->[ $Self->{XMLLevelCount}->{1}->{ $Self->{XMLLevelTag}->{1} } ]
|
|
->{ $Self->{XMLLevelTag}->{2} }
|
|
->[ $Self->{XMLLevelCount}->{2}->{ $Self->{XMLLevelTag}->{2} } ]
|
|
->{ $Self->{XMLLevelTag}->{3} }
|
|
->[ $Self->{XMLLevelCount}->{3}->{ $Self->{XMLLevelTag}->{3} } ]
|
|
->{ $Self->{XMLLevelTag}->{4} }
|
|
->[ $Self->{XMLLevelCount}->{4}->{ $Self->{XMLLevelTag}->{4} } ]
|
|
->{ $Self->{XMLLevelTag}->{5} }
|
|
->[ $Self->{XMLLevelCount}->{5}->{ $Self->{XMLLevelTag}->{5} } ]
|
|
->{ $Self->{XMLLevelTag}->{6} }
|
|
->[ $Self->{XMLLevelCount}->{6}->{ $Self->{XMLLevelTag}->{6} } ]
|
|
->{ $Self->{XMLLevelTag}->{7} }
|
|
->[ $Self->{XMLLevelCount}->{7}->{ $Self->{XMLLevelTag}->{7} } ]
|
|
->{ $Self->{XMLLevelTag}->{8} }
|
|
->[ $Self->{XMLLevelCount}->{8}->{ $Self->{XMLLevelTag}->{8} } ]
|
|
->{ $Self->{XMLLevelTag}->{9} }
|
|
->[ $Self->{XMLLevelCount}->{9}->{ $Self->{XMLLevelTag}->{9} } ]
|
|
->{ $Self->{XMLLevelTag}->{10} }
|
|
->[ $Self->{XMLLevelCount}->{10}->{ $Self->{XMLLevelTag}->{10} } ]
|
|
->{ $Self->{XMLLevelTag}->{11} }
|
|
->[ $Self->{XMLLevelCount}->{11}->{ $Self->{XMLLevelTag}->{11} } ]->{$_} = $Param{Item}->{$_};
|
|
}
|
|
}
|
|
}
|
|
elsif ( $Param{Item}->{TagLevel} == 12 ) {
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( !defined $Param{Item}->{$_} ) {
|
|
$Param{Item}->{$_} = '';
|
|
}
|
|
if ( $_ !~ /^Tag/ ) {
|
|
$Self->{XMLHash2}->{ $Self->{XMLLevelTag}->{1} }
|
|
->[ $Self->{XMLLevelCount}->{1}->{ $Self->{XMLLevelTag}->{1} } ]
|
|
->{ $Self->{XMLLevelTag}->{2} }
|
|
->[ $Self->{XMLLevelCount}->{2}->{ $Self->{XMLLevelTag}->{2} } ]
|
|
->{ $Self->{XMLLevelTag}->{3} }
|
|
->[ $Self->{XMLLevelCount}->{3}->{ $Self->{XMLLevelTag}->{3} } ]
|
|
->{ $Self->{XMLLevelTag}->{4} }
|
|
->[ $Self->{XMLLevelCount}->{4}->{ $Self->{XMLLevelTag}->{4} } ]
|
|
->{ $Self->{XMLLevelTag}->{5} }
|
|
->[ $Self->{XMLLevelCount}->{5}->{ $Self->{XMLLevelTag}->{5} } ]
|
|
->{ $Self->{XMLLevelTag}->{6} }
|
|
->[ $Self->{XMLLevelCount}->{6}->{ $Self->{XMLLevelTag}->{6} } ]
|
|
->{ $Self->{XMLLevelTag}->{7} }
|
|
->[ $Self->{XMLLevelCount}->{7}->{ $Self->{XMLLevelTag}->{7} } ]
|
|
->{ $Self->{XMLLevelTag}->{8} }
|
|
->[ $Self->{XMLLevelCount}->{8}->{ $Self->{XMLLevelTag}->{8} } ]
|
|
->{ $Self->{XMLLevelTag}->{9} }
|
|
->[ $Self->{XMLLevelCount}->{9}->{ $Self->{XMLLevelTag}->{9} } ]
|
|
->{ $Self->{XMLLevelTag}->{10} }
|
|
->[ $Self->{XMLLevelCount}->{10}->{ $Self->{XMLLevelTag}->{10} } ]
|
|
->{ $Self->{XMLLevelTag}->{11} }
|
|
->[ $Self->{XMLLevelCount}->{11}->{ $Self->{XMLLevelTag}->{11} } ]
|
|
->{ $Self->{XMLLevelTag}->{12} }
|
|
->[ $Self->{XMLLevelCount}->{12}->{ $Self->{XMLLevelTag}->{12} } ]->{$_} = $Param{Item}->{$_};
|
|
}
|
|
}
|
|
}
|
|
elsif ( $Param{Item}->{TagLevel} == 13 ) {
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( !defined $Param{Item}->{$_} ) {
|
|
$Param{Item}->{$_} = '';
|
|
}
|
|
if ( $_ !~ /^Tag/ ) {
|
|
$Self->{XMLHash2}->{ $Self->{XMLLevelTag}->{1} }
|
|
->[ $Self->{XMLLevelCount}->{1}->{ $Self->{XMLLevelTag}->{1} } ]
|
|
->{ $Self->{XMLLevelTag}->{2} }
|
|
->[ $Self->{XMLLevelCount}->{2}->{ $Self->{XMLLevelTag}->{2} } ]
|
|
->{ $Self->{XMLLevelTag}->{3} }
|
|
->[ $Self->{XMLLevelCount}->{3}->{ $Self->{XMLLevelTag}->{3} } ]
|
|
->{ $Self->{XMLLevelTag}->{4} }
|
|
->[ $Self->{XMLLevelCount}->{4}->{ $Self->{XMLLevelTag}->{4} } ]
|
|
->{ $Self->{XMLLevelTag}->{5} }
|
|
->[ $Self->{XMLLevelCount}->{5}->{ $Self->{XMLLevelTag}->{5} } ]
|
|
->{ $Self->{XMLLevelTag}->{6} }
|
|
->[ $Self->{XMLLevelCount}->{6}->{ $Self->{XMLLevelTag}->{6} } ]
|
|
->{ $Self->{XMLLevelTag}->{7} }
|
|
->[ $Self->{XMLLevelCount}->{7}->{ $Self->{XMLLevelTag}->{7} } ]
|
|
->{ $Self->{XMLLevelTag}->{8} }
|
|
->[ $Self->{XMLLevelCount}->{8}->{ $Self->{XMLLevelTag}->{8} } ]
|
|
->{ $Self->{XMLLevelTag}->{9} }
|
|
->[ $Self->{XMLLevelCount}->{9}->{ $Self->{XMLLevelTag}->{9} } ]
|
|
->{ $Self->{XMLLevelTag}->{10} }
|
|
->[ $Self->{XMLLevelCount}->{10}->{ $Self->{XMLLevelTag}->{10} } ]
|
|
->{ $Self->{XMLLevelTag}->{11} }
|
|
->[ $Self->{XMLLevelCount}->{11}->{ $Self->{XMLLevelTag}->{11} } ]
|
|
->{ $Self->{XMLLevelTag}->{12} }
|
|
->[ $Self->{XMLLevelCount}->{12}->{ $Self->{XMLLevelTag}->{12} } ]
|
|
->{ $Self->{XMLLevelTag}->{13} }
|
|
->[ $Self->{XMLLevelCount}->{13}->{ $Self->{XMLLevelTag}->{13} } ]->{$_} = $Param{Item}->{$_};
|
|
}
|
|
}
|
|
}
|
|
elsif ( $Param{Item}->{TagLevel} == 14 ) {
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( !defined $Param{Item}->{$_} ) {
|
|
$Param{Item}->{$_} = '';
|
|
}
|
|
if ( $_ !~ /^Tag/ ) {
|
|
$Self->{XMLHash2}->{ $Self->{XMLLevelTag}->{1} }
|
|
->[ $Self->{XMLLevelCount}->{1}->{ $Self->{XMLLevelTag}->{1} } ]
|
|
->{ $Self->{XMLLevelTag}->{2} }
|
|
->[ $Self->{XMLLevelCount}->{2}->{ $Self->{XMLLevelTag}->{2} } ]
|
|
->{ $Self->{XMLLevelTag}->{3} }
|
|
->[ $Self->{XMLLevelCount}->{3}->{ $Self->{XMLLevelTag}->{3} } ]
|
|
->{ $Self->{XMLLevelTag}->{4} }
|
|
->[ $Self->{XMLLevelCount}->{4}->{ $Self->{XMLLevelTag}->{4} } ]
|
|
->{ $Self->{XMLLevelTag}->{5} }
|
|
->[ $Self->{XMLLevelCount}->{5}->{ $Self->{XMLLevelTag}->{5} } ]
|
|
->{ $Self->{XMLLevelTag}->{6} }
|
|
->[ $Self->{XMLLevelCount}->{6}->{ $Self->{XMLLevelTag}->{6} } ]
|
|
->{ $Self->{XMLLevelTag}->{7} }
|
|
->[ $Self->{XMLLevelCount}->{7}->{ $Self->{XMLLevelTag}->{7} } ]
|
|
->{ $Self->{XMLLevelTag}->{8} }
|
|
->[ $Self->{XMLLevelCount}->{8}->{ $Self->{XMLLevelTag}->{8} } ]
|
|
->{ $Self->{XMLLevelTag}->{9} }
|
|
->[ $Self->{XMLLevelCount}->{9}->{ $Self->{XMLLevelTag}->{9} } ]
|
|
->{ $Self->{XMLLevelTag}->{10} }
|
|
->[ $Self->{XMLLevelCount}->{10}->{ $Self->{XMLLevelTag}->{10} } ]
|
|
->{ $Self->{XMLLevelTag}->{11} }
|
|
->[ $Self->{XMLLevelCount}->{11}->{ $Self->{XMLLevelTag}->{11} } ]
|
|
->{ $Self->{XMLLevelTag}->{12} }
|
|
->[ $Self->{XMLLevelCount}->{12}->{ $Self->{XMLLevelTag}->{12} } ]
|
|
->{ $Self->{XMLLevelTag}->{13} }
|
|
->[ $Self->{XMLLevelCount}->{13}->{ $Self->{XMLLevelTag}->{13} } ]
|
|
->{ $Self->{XMLLevelTag}->{14} }
|
|
->[ $Self->{XMLLevelCount}->{14}->{ $Self->{XMLLevelTag}->{14} } ]->{$_} = $Param{Item}->{$_};
|
|
}
|
|
}
|
|
}
|
|
elsif ( $Param{Item}->{TagLevel} == 15 ) {
|
|
for ( sort keys %{ $Param{Item} } ) {
|
|
if ( !defined $Param{Item}->{$_} ) {
|
|
$Param{Item}->{$_} = '';
|
|
}
|
|
if ( $_ !~ /^Tag/ ) {
|
|
$Self->{XMLHash2}->{ $Self->{XMLLevelTag}->{1} }
|
|
->[ $Self->{XMLLevelCount}->{1}->{ $Self->{XMLLevelTag}->{1} } ]
|
|
->{ $Self->{XMLLevelTag}->{2} }
|
|
->[ $Self->{XMLLevelCount}->{2}->{ $Self->{XMLLevelTag}->{2} } ]
|
|
->{ $Self->{XMLLevelTag}->{3} }
|
|
->[ $Self->{XMLLevelCount}->{3}->{ $Self->{XMLLevelTag}->{3} } ]
|
|
->{ $Self->{XMLLevelTag}->{4} }
|
|
->[ $Self->{XMLLevelCount}->{4}->{ $Self->{XMLLevelTag}->{4} } ]
|
|
->{ $Self->{XMLLevelTag}->{5} }
|
|
->[ $Self->{XMLLevelCount}->{5}->{ $Self->{XMLLevelTag}->{5} } ]
|
|
->{ $Self->{XMLLevelTag}->{6} }
|
|
->[ $Self->{XMLLevelCount}->{6}->{ $Self->{XMLLevelTag}->{6} } ]
|
|
->{ $Self->{XMLLevelTag}->{7} }
|
|
->[ $Self->{XMLLevelCount}->{7}->{ $Self->{XMLLevelTag}->{7} } ]
|
|
->{ $Self->{XMLLevelTag}->{8} }
|
|
->[ $Self->{XMLLevelCount}->{8}->{ $Self->{XMLLevelTag}->{8} } ]
|
|
->{ $Self->{XMLLevelTag}->{9} }
|
|
->[ $Self->{XMLLevelCount}->{9}->{ $Self->{XMLLevelTag}->{9} } ]
|
|
->{ $Self->{XMLLevelTag}->{10} }
|
|
->[ $Self->{XMLLevelCount}->{10}->{ $Self->{XMLLevelTag}->{10} } ]
|
|
->{ $Self->{XMLLevelTag}->{11} }
|
|
->[ $Self->{XMLLevelCount}->{11}->{ $Self->{XMLLevelTag}->{11} } ]
|
|
->{ $Self->{XMLLevelTag}->{12} }
|
|
->[ $Self->{XMLLevelCount}->{12}->{ $Self->{XMLLevelTag}->{12} } ]
|
|
->{ $Self->{XMLLevelTag}->{13} }
|
|
->[ $Self->{XMLLevelCount}->{13}->{ $Self->{XMLLevelTag}->{13} } ]
|
|
->{ $Self->{XMLLevelTag}->{14} }
|
|
->[ $Self->{XMLLevelCount}->{14}->{ $Self->{XMLLevelTag}->{14} } ]
|
|
->{ $Self->{XMLLevelTag}->{15} }
|
|
->[ $Self->{XMLLevelCount}->{15}->{ $Self->{XMLLevelTag}->{15} } ]->{$_} = $Param{Item}->{$_};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub _Decode {
|
|
my ( $Self, $A ) = @_;
|
|
|
|
# get encode object
|
|
my $EncodeObject = $Kernel::OM->Get('Kernel::System::Encode');
|
|
|
|
for ( sort keys %{$A} ) {
|
|
if ( ref $A->{$_} eq 'ARRAY' ) {
|
|
for my $B ( @{ $A->{$_} } ) {
|
|
$Self->_Decode($B);
|
|
}
|
|
}
|
|
|
|
# decode
|
|
elsif ( defined $A->{$_} ) {
|
|
|
|
# check if decode is already done by parser
|
|
if ( $Self->{XMLQuote} ) {
|
|
my %Map = (
|
|
'amp' => '&',
|
|
'lt' => '<',
|
|
'gt' => '>',
|
|
'quot' => '"',
|
|
);
|
|
$A->{$_} =~ s/&(amp|lt|gt|quot);/$Map{$1}/g;
|
|
}
|
|
|
|
# convert into default charset
|
|
$A->{$_} = $EncodeObject->Convert(
|
|
Text => $A->{$_},
|
|
From => 'utf-8',
|
|
To => 'utf-8',
|
|
Force => 1,
|
|
);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub _HS {
|
|
my ( $Self, $Expat, $Element, %Attr ) = @_;
|
|
|
|
if ( $Self->{LastTag} ) {
|
|
push @{ $Self->{XMLARRAY} }, { %{ $Self->{LastTag} }, Content => $Self->{C} };
|
|
}
|
|
|
|
undef $Self->{LastTag};
|
|
undef $Self->{C};
|
|
|
|
$Self->{XMLLevel}++;
|
|
$Self->{XMLTagCount}++;
|
|
$Self->{XMLLevelTag}->{ $Self->{XMLLevel} } = $Element;
|
|
|
|
if ( $Self->{Tll} && $Self->{Tll} > $Self->{XMLLevel} ) {
|
|
for ( ( $Self->{XMLLevel} + 1 ) .. 30 ) {
|
|
undef $Self->{XMLLevelCount}->{$_};
|
|
}
|
|
}
|
|
|
|
$Self->{XMLLevelCount}->{ $Self->{XMLLevel} }->{$Element}++;
|
|
|
|
# remember old level
|
|
$Self->{Tll} = $Self->{XMLLevel};
|
|
|
|
my $Key = '';
|
|
for ( 1 .. ( $Self->{XMLLevel} ) ) {
|
|
$Key .= "{'$Self->{XMLLevelTag}->{$_}'}";
|
|
$Key .= "[" . $Self->{XMLLevelCount}->{$_}->{ $Self->{XMLLevelTag}->{$_} } . "]";
|
|
}
|
|
|
|
$Self->{LastTag} = {
|
|
%Attr,
|
|
TagType => 'Start',
|
|
Tag => $Element,
|
|
TagLevel => $Self->{XMLLevel},
|
|
TagCount => $Self->{XMLTagCount},
|
|
TagLastLevel => $Self->{XMLLevelTag}->{ ( $Self->{XMLLevel} - 1 ) },
|
|
};
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub _CS {
|
|
my ( $Self, $Expat, $Element, $I, $II ) = @_;
|
|
|
|
if ( $Self->{LastTag} ) {
|
|
$Self->{C} .= $Element;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub _ES {
|
|
my ( $Self, $Expat, $Element ) = @_;
|
|
|
|
$Self->{XMLTagCount}++;
|
|
|
|
if ( $Self->{LastTag} ) {
|
|
push @{ $Self->{XMLARRAY} }, { %{ $Self->{LastTag} }, Content => $Self->{C} };
|
|
}
|
|
|
|
undef $Self->{LastTag};
|
|
undef $Self->{C};
|
|
|
|
push(
|
|
@{ $Self->{XMLARRAY} },
|
|
{
|
|
TagType => 'End',
|
|
TagLevel => $Self->{XMLLevel},
|
|
TagCount => $Self->{XMLTagCount},
|
|
Tag => $Element
|
|
},
|
|
);
|
|
|
|
$Self->{XMLLevel} = $Self->{XMLLevel} - 1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
1;
|
|
|
|
=end Internal:
|
|
|
|
=head1 TERMS AND CONDITIONS
|
|
|
|
This software is part of the OTRS project (L<https://otrs.org/>).
|
|
|
|
This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
|
the enclosed file COPYING for license information (GPL). If you
|
|
did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
|
|
|
|
=cut
|