【问题标题】:update node attribute with latest datetime in XML使用 XML 中的最新日期时间更新节点属性
【发布时间】:2014-04-09 06:34:12
【问题描述】:

我有以下 XML:

< measCollecFile>

    < fileHeader>

            < measCollec beginTime="2013-03-14T12:10:00+00:00" />

    </ fileHeader>

    < measData>

            < measInfo>
                    < granPeriod duration="PT300S" endTime="2013-03-14T12:15:00+00:00"  />
                    < measType>VS.ave</measType>
                    < measType>VS.aveCPU</measType>

                    < measValue>VS1</measValue>
                    < measValue>VS2</measValue>
            </ measInfo>
    </ measData>
</ measCollecFile>

问:我的问题我需要处理这个 XML 文件并修改某些元素中的少量数据。正如您从我之前的帖子中看到的那样,我可以在这个网站的帮助下做到这一点。

有一个新的挑战。如您所见,XML 中也有 datetime 元素。我需要以与 XML 中显示的相同格式将其更新为当前日期时间。即 XML 将始终包含任何日期,我只是为了找到日期时间标签并将其更新为当前日期时间,但它应该与那里的格式相同。

我是否应该将其视为单独的问题,并将其视为简单的正则表达式 Perl 问题并作为平面文件相应地解决查找和替换问题

LIBXML 有内置的东西来识别日期时间标签并用最新的日期时间更新它?

【问题讨论】:

    标签: xml regex perl datetime


    【解决方案1】:

    识别“日期时间”标签并没有什么特别之处。您当然可以寻找适合特定格式的属性,但这真的是您想要的吗?

    使用XML::LibXMLTime::Piece 将beginTime 替换为当前日期:

    use strict;
    use warnings;
    
    use XML::LibXML;
    use Time::Piece;
    
    my $date_format = '%Y-%m-%dT%H:%M:%S';
    
    my $data = do { local $/; <DATA> };
    
    my $dom = XML::LibXML->load_xml(string => $data);
    
    for my $node ($dom->findnodes('//*[@beginTime]')) {
        if ( my $begin = $node->getAttribute('beginTime') ) {
            my ($plaindate, $tz) = split '(?=\+)', $begin;
            my $date = Time::Piece->strptime($plaindate, $date_format);
            print "old beginTime = '$date'\n";
            my $newdate = localtime->strftime($date_format);
            $node->setAttribute('beginTime', $newdate . $tz);
        }
    }
    
    print $dom->toString();
    
    __DATA__
    <measCollecFile>
        <fileHeader>
            <measCollec beginTime="2013-03-14T12:10:00+00:00" />
        </fileHeader>
        <measData>
            <measInfo>
                <granPeriod duration="PT300S" endTime="2013-03-14T12:15:00+00:00"  />
                <measType>VS.ave</measType>
                <measType>VS.aveCPU</measType>
                <measValue>VS1</measValue>
                <measValue>VS2</measValue>
            </measInfo>
        </measData>
    </measCollecFile>
    

    要同时更新 beginTime 和 endTime,您可以创建一个更复杂的 xpath:

    my @attribs = qw(beginTime endTime);
    my $attribs_list = join ' | ', map {'@'.$_} @attribs;
    
    for my $node ($dom->findnodes("//*[$attribs_list]")) {
        for my $key (@attribs) {
            if ( my $att = $node->getAttribute($key) ) {
                my ($plaindate, $tz) = split '(?=\+)', $att;
                my $date = Time::Piece->strptime($plaindate, $date_format);
                print "old $key = '$date'\n";
                my $newdate = localtime->strftime($date_format);
                $node->setAttribute($key, $newdate . $tz);
            }
        }
    }
    

    【讨论】:

    • 嗨米勒。你摇滚!!这正是我想要的。唯一的问题是 beginTime 和 endTime 可能多次出现,并且可能出现在不同的深度。但我会事先知道一些事情:标签名称是什么,例如 beginTime、endTime 等,以及日期时间的格式。希望 findnode 仍然可以在 XML 的所有深度找到所有 beginTime。我可能需要始终保持开始时间和结束时间之间的增量时间差。
    • 我提供的 xpaths 将找到所有具有上述属性的节点。只要您可以编写所需的更改逻辑,这些都应该有效。
    • 不确定,但第二个在我包含两个节点 qw(beginTime endTime) 的情况下不起作用。查找节点没有找到任何东西?
    • 哎呀,它确实有效!实际上我使用了 parse_file 而不是 load_xml。因为我还必须更新许多其他领域。所以似乎我需要用 parse_file 做两次,下一次用 load_xml 做日期时间?
    • 加载xml的方法无关紧要。我只使用了 load_XML,因为它使我能够创建一个工作示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-22
    相关资源
    最近更新 更多