【问题标题】:XML::Twig - identifying blobs that do not contain an elementXML::Twig - 识别不包含元素的 blob
【发布时间】:2017-10-10 08:29:21
【问题描述】:

我正在使用 XML::Twig 解析 Azure 的 list-blob REST API 的输出。

特别是,我希望识别和删除未提交的孤立 blob,但我不确定如何最好地有效地使用 XML::Twig 来执行此操作。我什至不知道从哪里开始。

最终我需要检索孤立 blob 的 <Name> 元素。

Azure documentation 声明:

响应中未提交的 Blob

只有当 include=uncommittedblobs 参数是在 URI 上指定的。 响应中列出的未提交 blob 不包括任何 以下元素:

Last-Modified
Etag
Content-Type
Content-Encoding
Content-Language
Content-MD5
Cache-Control
Metadata

因此,在下面的简化示例中,您可以看到一个名为“test”的孤立 blob,因为 <Blob></Blob> 块不包含上述任何元素。

<?xml version="1.0" encoding="utf-8"?>
<EnumerationResults ServiceEndpoint="https://my**account.blob.core.windows.net/"
  ContainerName="testonly">
  <Blobs>
    <Blob>
      <Name>test</Name>
      <Properties>
        <Content-Length>0</Content-Length>
        <BlobType>BlockBlob</BlobType>
        <LeaseStatus>unlocked</LeaseStatus>
        <LeaseState>available</LeaseState>
      </Properties>
    </Blob>
  </Blobs>
  <NextMarker/>
</EnumerationResults>

更新:

实际上,我可能过于简单化了。接受的答案似乎不适用于以下内容,它会打印所有内容:

<?xml version="1.0" encoding="utf-8"?>
<EnumerationResults ServiceEndpoint="https://my**account.blob.core.windows.net/" ContainerName="testonly">
<Blobs>
    <Blob>
        <Name>data/users/docx</Name>
        <Properties>
            <Last-Modified>Wed, 10 May 2017 20:21:25 GMT</Last-Modified>
            <Etag>0x8D497E221E7A5AF</Etag>
            <Content-Length>125632</Content-Length>
            <Content-Type>application/octet-stream</Content-Type>
            <Content-Encoding/>
            <Content-Language/>
            <Content-MD5/>
            <Cache-Control/>
            <Content-Disposition/>
            <BlobType>BlockBlob</BlobType>
            <LeaseStatus>unlocked</LeaseStatus>
            <LeaseState>available</LeaseState>
        </Properties>
    </Blob>
    <Blob>
        <Name>test</Name>
        <Properties>
            <Content-Length>0</Content-Length>
            <BlobType>BlockBlob</BlobType>
            <LeaseStatus>unlocked</LeaseStatus>
            <LeaseState>available</LeaseState>
        </Properties>
    </Blob>
</Blobs>
<NextMarker/>
</EnumerationResults>

我的代码:

sub blob_parse {
        my $blob = $_;
        $blob->first_child($_) and return
        for qw( Last-Modified Etag Content-Type Content-Encoding
                Content-Language Content-MD5 Cache-Control Metadata);
        say "orph: ".$blob->first_child('Name')->text;
}

sub parseAndDelete {
        ### ORPHAN
        $twig_handlers = {'Blobs/Blob' => \&blob_parse};
        $twig = new XML::Twig(twig_handlers=>$twig_handlers);
        $twig->parse($message);
}

【问题讨论】:

  • 所以您是说 XML 格式错误,带有结束 &lt;/Blob&gt; 标记但没有开始 &lt;Blob&gt;?我怀疑XML::Twig 是否会处理这个问题。
  • @Borodin 不!那只是我的复制粘贴失败(通过 TMUX 从 Linux 复制/粘贴有时会做一些奇怪的事情。我已经修复了它。
  • 我发现了。我已经更新了我的答案,并在 choroba's 的评论中进行了修复。你可以选择任何你喜欢的!

标签: perl xml-parsing azure-storage xml-twig


【解决方案1】:

更新

没有理由使用XML::Twig 提供的回调系统,除非您的 XML 数据非常庞大并且相应的数据结构占用了太多内存,而这对于从互联网消息中获取的数据来说不太可能

我会这样实现

use strict;
use warnings;
use feature 'say';

use XML::Twig;
use List::Util 'none';

my @unwanted = qw/
    Last-Modified Etag Content-Type Content-Encoding
    Content-Language Content-MD5 Cache-Control Metadata
/;

my $twig = 'XML::Twig'->new;

$twig->parsefile('blob.xml');

for my $blob ( $twig->find_nodes('Blobs/Blob') ) {

    if ( none { $blob->find_nodes("Properties/$_") } @unwanted ) {
        say $_->text for $blob->find_nodes('Name');
    }
}

输出

test



如果您的 XML 实际上格式正确,而您的示例数据有误,那么打印所有 Name 元素的文本内容很简单

我用过这个数据

<?xml version="1.0" encoding="utf-8"?>
<EnumerationResults ServiceEndpoint="https://my**account.blob.core.windows.net/"
  ContainerName="testonly">
  <Blobs>
    <Blob>
      <Name>test</Name>
      <Properties>
        <Content-Length>0</Content-Length>
        <BlobType>BlockBlob</BlobType>
        <LeaseStatus>unlocked</LeaseStatus>
        <LeaseState>available</LeaseState>
      </Properties>
    </Blob>
  </Blobs>
  <NextMarker/>
</EnumerationResults>

Perl

use strict;
use warnings 'all';
use feature 'say';

use XML::Twig;

my $t = XML::Twig->new;
$t->parsefile( 'blob.xml');

say $_->text for $t->find_nodes('Blobs/Blob/Name');

输出

test

【讨论】:

  • " 打印所有 Name 元素的文本内容很简单" .... 是的,我已经想出了一个 .... 我的问题的重点是我想要一个元素的子集. list-blob 返回所有内容,我只想要按照我发布的文档摘录的孤儿。我认为@choroba 有答案。
  • @LittleCode: 对不起,我试图了解 uncommitedorphan blob 之间的关系(您展示了 uncommited blobs,并且不再使用该术语)以及这是否意味着缺少开始标记的 &lt;Blob&gt; 元素。您的示例数据恰好显示了一个 &lt;Blob&gt; 并且您想要它的名称,而我的代码可以正常使用。最好解释您的术语并提供一些需要过滤的数据,这是您问题的重点。幸运的是 choroba 了解您的意图。
  • 没问题,我试图让我的示例保持简单,但我想我过于简单了!
  • @LittleCode:我已经更新了我的答案。您可能更喜欢避免使用回调并仅构建可以导航的静态数据结构的解决方案。我还修复了 choroba 的 示例中的一个错误,即他在错误的位置查找不能出现在消息中的元素。
  • @LittleCode:我已经根据你的新数据测试了我的更新,它工作正常。
【解决方案2】:

只需为Blob 创建一个处理程序,如果存在任何元素,则不执行任何操作,否则打印名称。使用 first_child 方法检查 blob 的内部结构。

#! /usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

use XML::Twig;

my $xml = '...';

my $twig = 'XML::Twig'->new(twig_handlers => {
    Blob => sub {
        my $properties = $_->first_child('Properties');
        $properties->first_child($_) and return
            for qw( Last-Modified Etag Content-Type Content-Encoding
                    Content-Language Content-MD5 Cache-Control Metadata
                  );
        say $_->first_child('Name')->text;
    },
});
$twig->parse($xml);

【讨论】:

  • 我认为这需要my $properties = $blob-&gt;first_child('Properties')$properties-&gt;first_child($_) and return ...
  • @Borodin 我正在对此进行重新测试...根据我在下面对您的评论,它实际上不适用于“真实”数据...适合我过度简化我的样本!我已经用添加的数据更新了我的问题。
  • 根据新样本更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-09
相关资源
最近更新 更多