选择特定节点属性

问题描述 投票:0回答:1

我在从文档中选择一些特定的XML数据时遇到了一些麻烦。基础数据是营销活动。每个文档可以有多个事件。每个活动的内部都有多名与会者和注册人。我开始在SelectNodes()循环中使用foreach并在转换为CSV之前将其读入哈希表。

对于单个事件,这似乎工作正常,但对于多个事件,行不一致,偶数与其他记录数据不同步。我现在正在考虑将整个XML导出为CSV并让ETL工具从那里获得控制权。

我的理解存在差距,并且想知道是否有人知道如何将多个特定XML属性选择到CSV中,但它保持序列顺序。

我的PowerShell代码:

cls
[xml]$xml = Get-Content ("D:\sample.xml")

$dataTable  = @()
$eventNodes = $xml.SelectNodes('//event')
foreach ($event in $eventNodes) {
    $eventid    = $event.eventid
    $eventtitle = $event.eventtitle.InnerText               
    $eventtime  = $event.eventtime                           

    # get registrant data
    $registrantNodes = $xml.SelectNodes('//registrant')
    foreach ($registrant in $registrantNodes) {
        $firstname = $registrant.firstname.InnerText
        $lastname  = $registrant.lastname.InnerText
        $city      = $registrant.city.InnerText
        $state     = $registrant.state.InnerText    
        $country   = $registrant.country.InnerText
        $company   = $registrant.company.InnerText
        $workphone = $registrant.workphone.InnerText    
        $email     = $registrant.email.InnerText

        # get attendee data
        $attendeeNodes = $xml.SelectNodes('//attendee')
        foreach ($attendee in $attendeeNodes) {
            $attendedlive    = $attendee.attendedlive.InnerText
            $attendedarchive = $attendee.attendedarchive.InnerText

            # put all data into holding table
            $dataEntry = New-Object PSObject -Property @{
                FirstName       = $firstname;
                LastName        = $lastname;
                City            = $city;
                State           = $state;
                Country         = $country;
                Company         = $company;
                WorkPhone       = $workphone;
                Email           = $email;
                AttendedLive    = $attendedlive;
                AttendedArchive = $attendedarchive;
                EventID         = $eventid;
                EventTitle      = $eventtitle;
                EventTime       = $eventtime;
                Orginization    = 'North America';
            }
            $dataTable += $dataEntry
        }
    }
}

# display holding table
$dataTable

$dataTable | Export-Csv -Force -Path "D:\output.csv" -NoTypeInformation

我上传了一个示例XML文件here。布局如下所示:

XML layout

xml powershell
1个回答
1
投票

您的主要问题是所有XPath都是绝对路径 - 它们都从文档的根开始。当您查询//registrant时,XML文档不会神奇地为您提供属于您在本特定代码行中所谓的“当前”事件的所有注册人。它将为您提供所有活动的所有注册人,因为这就是您所要求的。如果您想要相对结果,请使用相对导航,即以当前元素(XPath中的.)开头的XPath,如本例所示。

您的第二个问题是注册人和与会者通过eventuserid相互关联。您不能简单地查询任何注册人,您必须考虑该ID才能选择正确的ID。你的代码没有这样做,幸运的是它在XPath中非常简单。

你的第三个问题是你从上到下看整个任务。活动 - 注册人 - 与会者。这就是你的XML的结构,但实际上你需要每个与会者的CSV中有一个输出行,并为该人提供一些相关数据。因此,自下而上这样做是明智的:首先是与会者,然后是相应的注册人和事件。

考虑以下代码:

cls

$xml = New-Object xml
$xml.Load("D:\sample.xml")

$allAttendees = $xml.SelectNodes('//attendee') | ForEach-Object {
    $attendee = $_
    $event = $attendee.SelectSingleNode('./ancestor::event[1]')
    $registrant = $event.SelectSingleNode("./registrants/registrant[eventuserid = '$($attendee.eventuserid)']")
    New-Object PSObject -Property @{
        FirstName       = $registrant.firstname
        LastName        = $registrant.lastname
        City            = $registrant.city
        State           = $registrant.state
        Country         = $registrant.country
        Company         = $registrant.company
        WorkPhone       = $registrant.workphone
        Email           = $registrant.email
        AttendedLive    = $attendee.attendedlive
        AttendedArchive = $attendee.attendedarchive
        EventID         = $event.eventid;
        EventTitle      = $event.eventtitle
        EventTime       = $event.eventtime
        Orginization    = 'North America';
    }
}

$allAttendees | Export-Csv -Force -Path "D:\output.csv" -NoTypeInformation

笔记

  • 所有XPath都在某个节点上调用,并以.开头以引用该节点。
  • 您在PowerShell中的脚本块内生成并且不存储在变量中的所有值都将成为该脚本块的返回值的一部分。这就是ForEach-Object体生成一个对象数组而不需要将它们添加到临时变量的方式。这就是$allAttendees的任务如何在上面工作。
  • 要阅读的内容:XPath谓词和XPath轴以及字符串插值如何在Powershell中工作,以防你不熟悉"...$($attendee.eventuserid)..."结构。
  • 明确使用.InnerText是多余的。 Powershell会自动为您完成。
© www.soinside.com 2019 - 2024. All rights reserved.