Как мне динамически генерировать XML? - PullRequest
1 голос
/ 24 апреля 2011

Я действительно задавал этот вопрос в другой форме раньше. Я получил отличный ответ, но подумал, что мне нужно больше разъяснений, поэтому я снова прошу его в полном виде.

Пользователь может написать что-то вроде:

$ABC->Command(100, 100);
my $group  = "1";
my $id     = "1";
my $value1 = "Some Process A Happened";
$rep->getParameter($group, $id, $value1);
$ABC->Command(100, 100);
my $group  = "1";
my $id     = "2";
my $value1 = "Some Process B Happened";
$rep->getParameter($group, $id, $value1);
$ABC->Command(100, 100);
my $group  = "2";
my $id     = "1";
my $value1 = "Some Process A Happened";
$rep->getParameter($group, $id, $value1);
$ABC->Command(100, 100);
my $group  = "2";
my $id     = "1";
my $value1 = "Some Process Happened";
$rep->getParameter($group, $id, $value1);
$ABC->Command(100, 100);
my $group  = "3";
my $id     = "1";
my $value1 = "Some Process Happened";
$rep->getParameter($group, $id, $value1);
$ABC->SomeImage($image) $desc = "Some info";
$rep->getImage($image, $desc);
$rep->getResult("Pass")

Это должно сгенерировать XML как:

<?xml version="1.0" encoding="UTF-8" ?>
<TestResult xmlns="http://test.com/automate" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://test.com/automate">
    <Result>Pass</Result>
    <Comments>Executed Successfully</Comments>
    <Parameters>
        <ParameterGroup ID="Group1">
            <Parameter key="Key1">Some Value</Parameter>
            <Parameter key="Key2">Some Value</Parameter>
            <Parameter key="Key3">Some Value</Parameter>
        </ParameterGroup>
        <ParameterGroup ID="Group2">
            <Parameter key="Key1">Some Value</Parameter>
            <Parameter key="Key2">Some Value</Parameter>
            <Parameter key="Key3">Some Value</Parameter>
        </ParameterGroup>
        <ParameterGroup ID="Group3">
            <Parameter key="Key1">Some Value</Parameter>
            <Parameter key="Key2">Some Value</Parameter>
            <Parameter key="Key3">Some Value</Parameter>
        </ParameterGroup>
    </Parameters>
    <Images>
        <Image key="ImageTag1">info</Image>
        <Image key="ImageTag2">info</Image>
        <Image key="ImageTag3">info</Image>
    </Images>
</TestResult>

Значения изображения и значения параметров будут вводиться в разные моменты времени. Но их нужно было бы собрать и поместить в элемент Images, аналогично для Parameters. Какой подход я должен следовать здесь? Некоторые примеры кода, пожалуйста.


изм

У меня есть что-то вроде

$xml = {
    ParameterGroup => [
        {
            ID        => 'Group1',
            Parameter => {
                Key1  => {content => 'Some Value'},
                Key2  => {content => 'Some Value'},
                Key3  => {content => 'Some Value'},
            },
        },
        {
            ID        => 'Group2',
            Parameter => {
                Key1  => {content => 'Some Value'},
                Key2  => {content => 'Some Value'},
                Key3  => {content => 'Some Value'},
            },
        },
    ]
};
print XMLout(
    $xml,
    RootName => 'Parameters',
    KeyAttr  => 'value',
);

как структура, но это фиксированные структуры. Как я могу сделать эту динамику в соответствии с требованиями пользователей?

Ответы [ 2 ]

2 голосов
/ 26 апреля 2011

Рассмотрим несколько небольших настроек кода вашего драйвера, приведенных ниже.

#! /usr/bin/env perl

use warnings;
use strict;

use TestResult;

my $tr = TestResult->new;

$tr->parameter(1, 1, "Some Process A Happened");
$tr->parameter(1, 2, "Some Process B Happened");
$tr->parameter(2, 1, "Some Process A Happened");
$tr->parameter(3, 1, "Some Process Happened");

$tr->image(1, "Some info");

$tr->result("Pass");
$tr->comments("Executed Successfully");

print $tr->as_xml;

Вывод XML:

<?xml version="1.0" encoding="UTF-8" ?>
<TestResult xmlns="http://test.com/automate" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://test.com/automate">
  <Result>Pass</Result>
  <Comments>Executed Successfully</Comments>
  <Parameters>
    <ParameterGroup ID="Group1">
      <Parameter key="Key1">Some Process A Happened</Parameter>
      <Parameter key="Key2">Some Process B Happened</Parameter>
    </ParameterGroup>
    <ParameterGroup ID="Group2">
      <Parameter key="Key1">Some Process A Happened</Parameter>
    </ParameterGroup>
    <ParameterGroup ID="Group3">
      <Parameter key="Key1">Some Process Happened</Parameter>
    </ParameterGroup>
  </Parameters>
  <Images>
    <Image key="ImageTag1">Some info</Image>
  </Images>
</TestResult>

Просмотр содержимого $self->{_xml} может помочь вашему пониманию.

{
  'Comments' => { 'content' => 'Executed Successfully' },
  'Parameters' => {
    'ParameterGroup' => {
      'Group1' => {
        'Parameter' => {
          'Key2' => { 'content' => 'Some Process B Happened' },
          'Key1' => { 'content' => 'Some Process A Happened' }
        }
      },
      'Group3' => {
        'Parameter' => {
          'Key1' => { 'content' => 'Some Process Happened' }
        }
      },
      'Group2' => {
        'Parameter' => {
          'Key1' => { 'content' => 'Some Process A Happened' }
        }
      }
    }
  },
  'xmlns' => 'http://test.com/automate',
  'Result' => { 'content' => 'Pass' },
  'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
  'xsi:schemaLocation' => 'http://test.com/automate',
  'Images' => {
    'ImageTag1' => { 'content' => 'Some info' }
  }
}

Модуль TestResult, который доставит вас туда, находится ниже. Обязательно поместите его в файл с именем TestResult.pm где-нибудь в пути поиска модуля. Все начинается со знакомого шаблона.

package TestResult;

use strict;
use warnings;

use XML::Simple;

Во время компиляции мы настраиваем подкласс XML :: Simple, специфичный для вашего желаемого формата XML, который будет выводить элементы в соответствующем порядке.

BEGIN {
  @__PACKAGE__::XML::ISA = qw/ XML::Simple /;

  my %order = (
    TestResult => [qw/
      xmlns xmlns:xsi xsi:schemaLocation
      Result Comments Parameters Images
    /],
  );

  *__PACKAGE__::XML::sorted_keys = sub {
    my($self,$name,$h) = @_;
    return @{ $order{$name} } if $order{$name};
    sort keys %$h;
  };
}

Каждый экземпляр будет содержать содержимое выходного документа. Жестко закодированные пары ключ-значение становятся атрибутами элемента TestResult.

sub new {
  my($class) = @_;
  my $self = {
    _xml => {
      "xmlns"              => "http://test.com/automate",
      "xmlns:xsi"          => "http://www.w3.org/2001/XMLSchema-instance",
      "xsi:schemaLocation" => "http://test.com/automate",
    },
  };

  bless $self => $class;
}

Реализации comments и result просты, потому что XML, который они создают, прост. Методы заполняют биты в соответствующих слотах без сюрпризов.

sub comments {
  my($self,$comments) = @_;
  $self->{_xml}{Comments} = { content => $comments };
}

sub result {
  my($self,$result) = @_;
  $self->{_xml}{Result} = { content => $result };
}

Мы должны быть осторожны с image и parameter, потому что они содержат несколько детей. Слепая перезапись $self->{_xml}{Images} или $self->{_xml}{Parameter} приведет к засорению любого контента, который уже был накоплен, поэтому вместо этого мы добавляем новые элементы постепенно.

sub image {
  my($self,$image,$desc) = @_;

  my $imageid = "ImageTag" . $image;
  $self->{_xml}{Images}{$imageid} = { content => $desc };
}

sub parameter {
  my($self,$group,$key,$value) = @_;

  my $groupid = "Group" . $group;
  my $keyid   = "Key"   . $key;

  $self->{_xml}{Parameters}{ParameterGroup}{$groupid}{Parameter}{$keyid} =
    { content => $value };
}

Наконец, мы кодируем XML, используя TestResult :: XML. Параметр GroupTags объявляет отношения вложенности, , например, , <Images> содержит <Image>. (Сначала я попытался дать аналогичную обработку отношениям между <Parameters> и <ParameterGroup> и между <ParameterGroup> и <Parameter>, но вывод XML отличался от того, что вы хотите.) Параметр KeyAttr сообщает XML :: Простой в использовании хеш-ключи Perl в качестве атрибутов XML. Префиксы + дадут более хорошие результаты, если вы когда-либо будете использовать XMLin для чтения TestResults, сгенерированных другими инструментами.

sub as_xml {
  my($self) = @_;

  my $serialize = __PACKAGE__::XML->new;

  $serialize->XMLout(
    $self->{_xml},
    GroupTags => {
      Images => "Image",
    },
    KeyAttr => {
      ParameterGroup => "+ID",
      Parameter      => "+key",
      Image          => "+key",
    },
    RootName => "TestResult",
    XMLDecl => '<?xml version="1.0" encoding="UTF-8" ?>',
  );
}

Возвращает истинное значение, указывающее, что модуль успешно загружен.

1;
1 голос
/ 24 апреля 2011

XML :: Simple ожидает, что вы соберете свой вывод в структуру данных perl, а затем преобразует его в XML; у вас возникли проблемы с фактическим вызовом для создания XML, с выяснением того, как должна выглядеть структура данных, или с заполнением ее вашими данными? (Или что-то совсем другое?)

Разбейте свою проблему и решите ее по одному.

...