如何动态生成 XML?

发布于 2024-11-03 06:31:50 字数 3336 浏览 0 评论 0原文

我实际上之前以不同的形式问过这个问题。我确实得到了一个很好的答案,但我认为我需要更多的澄清,所以我再次以完整的形式询问它。

用户将编写如下脚本:

$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',
);

结构的东西,但这些是固定结构。我怎样才能使这种动态满足用户的要求?

I actually asked this question in a different form before. I did get a great answer but I thought I needed more clarifications, so I am asking it in its whole form again.

The user would script something like:

$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")

This would have to generate an XML like:

<?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>

The image values and parameter values will be input at different points of time. But they would have to be collected and placed inside the Images element, similarly for Parameters. What approach should I follow here? Some code samples, please.


edited:

I have something like

$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',
);

as the structure but these are fixed structures. How can I make this dynamic to suit the users' requirement?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

白昼 2024-11-10 06:31:50

请考虑对您的驱动程序代码进行以下一些小调整。

#! /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 格式设置了 XML::Simple 的子类,它将按适当的顺序输出元素。

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;
}

commentsresult 的实现很简单,因为它们生成的 XML 很简单。这些方法毫无意外地将位填充到适当的槽中。

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

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

我们必须小心 imageparameter 因为它们包含多个子项。盲目覆盖 $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 };
}

最后,我们使用 TestResult::XML 对 XML 进行编码。 GroupTags 参数声明嵌套关系,例如 包含。 (首先,我尝试对 之间以及 ,但 XML 输出与您想要的不同。)KeyAttr 参数告诉 XML::Simple 使用 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" ?>',
  );
}

返回 true 值表示模块加载成功。

1;

Consider a few small adjustments below to your driver code.

#! /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;

The XML output is

<?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>

Seeing a dump of the contents of $self->{_xml} may aid your understanding.

{
  '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' }
  }
}

The TestResult module that gets you there is below. Be sure to put it in a file named TestResult.pm somewhere in the module search path. It begins with familiar boilerplate.

package TestResult;

use strict;
use warnings;

use XML::Simple;

At compile time, we set up a subclass of XML::Simple specific to your desired XML format that will output elements in the appropriate order.

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;
  };
}

Each instance will carry the contents of the output document. The hardcoded key-value pairs become attributes of the TestResult element.

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;
}

The implementations of comments and result are simple because the XML they produce is simple. The methods stuff bits in the appropriate slots with no surprises.

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

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

We have to be careful with image and parameter because they contain multiple children. Blindly overwriting $self->{_xml}{Images} or $self->{_xml}{Parameter} would clobber any content that had already been accumulated, so instead we add new elements incrementally.

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 };
}

Finally, we encode the XML using TestResult::XML. The GroupTags parameter declares nesting relationships, e.g., <Images> contains <Image>. (At first, I tried giving similar treatment to the relationships between <Parameters> and <ParameterGroup> and between <ParameterGroup> and <Parameter>, but the XML output differed from what you want.) The KeyAttr parameter tells XML::Simple to use Perl hash-keys as XML attributes. The + prefixes will make for nicer results if you ever use XMLin to read TestResults generated by other tools.

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" ?>',
  );
}

Return a true value to indicate that the module loaded successfully.

1;
缱倦旧时光 2024-11-10 06:31:50

XML::Simple 期望您将输出组装成 Perl 数据结构,然后将其转换为 XML;您在实际调用生成 XML、弄清楚数据结构应该是什么样子或用数据填充它时是否遇到困难? (或者完全不同的东西?)

分解你的问题并一次一点点地解决它。

XML::Simple expects you to assemble your output into a perl datastructure and then it converts it to XML; are you having trouble with the actual call to produce the XML, with figuring out what the datastructure should look like, or with populating it with your data? (Or something completely different?)

Break your problem down and solve it one bit at a time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文