You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CSV数据更新XML的Perl脚本报错及功能实现问题

Fixing Your Perl Script for XML Template Replacement

Let's break down and fix the issues you're facing:

Key Problems in the Original Script

  • The name value isn't a separate tag—it's an attribute of the root <ns0:networkdevice> element, so look_down('_tag' => 'name') returns undef, causing the push_content error.
  • Your code was trying to output the original unmodified XML tree ($tree) instead of each processed template for every CSV row.
  • The ipaddress lookup wasn't targeting the correct nested element (it's buried inside <NetworkDeviceIP> under <NetworkDeviceIPList>).

Modified Working Script

#!/usr/bin/perl
use warnings;
use strict;
use Text::CSV;
use XML::TreeBuilder;

my $xmlbase = 'template.xml';
my $paramsfile = 'input.csv';
# Map CSV columns to their XML target: attribute or nested tag
my @field_map = (
    { type => 'attr', target_tag => 'networkdevice', attr_name => 'name' },
    { type => 'tag',  target_tag => 'ipaddress', parent_path => ['NetworkDeviceIPList', 'NetworkDeviceIP'] }
);

my $csv = Text::CSV->new({ binary => 1 }) or die "Cannot use CSV: " . Text::CSV->error_diag();
open my $fh, "<:encoding(utf8)", $paramsfile or die "$paramsfile: $!";

# Uncomment below if your Input.csv has a header row (e.g., Name, IP Address)
# $csv->getline($fh);

while ( my $row = $csv->getline($fh) ) {
    # Load fresh template for each device to avoid cross-row contamination
    my $contree = XML::TreeBuilder->new();
    $contree->parsefile($xmlbase);
    
    my $index = 0;
    foreach my $field (@field_map) {
        my $value = $row->[$index++];
        next unless defined $value;
        
        if ($field->{type} eq 'attr') {
            # Update root element's name attribute
            my $root = $contree->look_down('_tag' => $field->{target_tag});
            $root->attr($field->{attr_name}, $value) if $root;
        } elsif ($field->{type} eq 'tag') {
            # Traverse nested path to find the parent of ipaddress
            my $parent_node = $contree;
            foreach my $path_part (@{$field->{parent_path}}) {
                $parent_node = $parent_node->look_down('_tag' => $path_part);
                last unless $parent_node;
            }
            # Replace existing ipaddress content with CSV value
            if ($parent_node) {
                my $ip_tag = $parent_node->look_down('_tag' => $field->{target_tag});
                $ip_tag->replace_content($value) if $ip_tag;
            }
        }
    }
    
    # Output the processed XML for this device (or save to a file)
    print '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
    print $contree->as_XML() . "\n\n";
    
    # Clean up to prevent memory leaks
    $contree->delete();
}

close $fh;

What Changed & Why

  1. Field Mapping Structure: We use an array of hashes to clearly define if each CSV field targets an XML attribute or a nested tag. This makes the script easier to adjust if your XML structure changes later.
  2. Handling the name Attribute: We directly target the root <ns0:networkdevice> element (XML::TreeBuilder automatically strips namespace prefixes from tag names) and use the attr() method to set its name property—this fixes the push_content error entirely.
  3. Nested ipaddress Update: We traverse the XML hierarchy step-by-step (NetworkDeviceIPList → NetworkDeviceIP) to find the correct parent of the ipaddress tag, then use replace_content() to overwrite its default value (instead of appending to it with push_content).
  4. Per-Row Template Freshness: We load a new template instance for every CSV row to ensure changes from one device don't leak into the next.
  5. Memory Management: Added $contree->delete() after processing each device to free up memory, which is helpful if you have a large CSV file.

Optional Enhancements

  • If your Input.csv includes a header row, uncomment the line that skips it to avoid processing the header as a device entry.
  • Instead of printing to the console, you could save each processed XML to a unique file (e.g., LAB-1.xml) by adding file-handling code inside the loop.

内容的提问来源于stack exchange,提问作者StayCalm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:43:40