0

我目前正在尝试将一些 XML 文档输入脚本并将它们初始化为[PSCustomObject]. XML 文档需要分成几个对象,然后添加到一起。

这是我的脚本:

[xml]$CourseStructureIn = Get-Content .\Sample.xml

$data = foreach ($Instances in $CourseStructureIn.Node.instances.courseInstance) {
    $instancearray = foreach ($instance in $instances) {
        $hash = [ordered]@{ CourseInstanceID = $instance.courseInstanceID}

        [PSCustomObject]@{
            CourseCode = $instance.CourseCode
            InstanceCode = $instance.instanceCode
            session = $instance.session
            quota = $instance.quota
        }
    }
    $hash.Add("Instances", $instancearray)

    $modules = $instance.L1Modules.L1Module
    $modulearray = foreach ($module in $modules) {
        [PSCustomObject]@{
            moduleCode = $module.moduleCode 
            moduleTypeCode = $module.moduleTypeCode
            moduleInstanceID = $module.moduleInstanceID
            semester = $module.semester
            credits = $module.credits
            overallGradeWeighting = $module.overallGradeWeighting
            fees = $module.fees
            documents = $module.documents
        }
    }
    $hash.Add("Modules", $modulearray)

    $roles = $instance.L1Modules.L1Module.roles.role
    $rolearray = foreach ($role in $roles) {
        [PSCustomObject]@{
            rolesGUID = $role.GUID
            rolesIDNumber = $role.idnumber
            roleFirstName = $role.firstname
            roleSurname = $role.surname
        }
    }
    $hash.Add("Roles", $rolearray)

这将 XML 结构正确地导入到对象数组的 2 个不同实例中——我应该提到 XML 最初来自规范化数据库,因此每个 XML 文档或多或少代表一个表——最终成为 PowerShell 中的多维数组。

$data.GetType()

IsPublic IsSerial 名称 BaseType
-------- -------- ---- --------
真真对象[] System.Array

我可以参考各个数组对象

$data[0].角色 | 英尺

角色GUID 角色IDNumber 角色名字角色姓氏
--------- ------------- ------------- -----------
55001420 55001420 RM
55001414 55001414 SC
55001234 55001234 CH
55001342 55001342 超频
55001414 55001414 SC
55001342 55001342 超频
55001445 55001445 毫米
55001422 55001422 啊
55001001 55001001 下午
55001079 55001079 对
55000770 55000770 上午
55000906 55000906 MB

我希望能够ConverTo-Html制作报告 - 但我不知道如何枚举这种类型的结构 - 我应该留下一个具有一对多关系的表(这是多维数组还是锯齿状数组?)可以有人给我一些关于如何输出这些类型的结构的指示吗?当输出是某种类型的矩阵时,遍历数组或对象很好 - 但是当结构对于某些列是多行而对于其他列是单行时,我们应该使用什么。

例如我的输出Format-Table

$数据 | 英尺

CourseInstanceID 实例模块
---- --------- --------
PGD​​DA_353650876 @{课程代码=PGDDA; 实例代码=PGDSP;会话=2014;配额=999;实例=; CourseInstanceID=PGDDA_353650876; 模块=System.Object[]; 角色=System.Object[]} {@{moduleCode=H...
PGD​​DA_418403503 @{课程代码=PGDDA; 实例代码=PGDSP;会话=2015;配额=999;实例=; CourseInstanceID=PGDDA_418403503; 模块=System.Object[]; 角色=System.Object[]} {@{moduleCode=H...

我已经尝试扩展属性并且已经在整个网络上阅读,所以任何指针将不胜感激。

以下是成员:

    $数据 | 通用汽车

       类型名称:System.Management.Automation.PSCustomObject

    名称 MemberType 定义
    ---- ---------- ----------
    Equals Method bool Equals(System.Object obj)
    GetHashCode 方法 int GetHashCode()
    GetType 方法类型 GetType()
    ToString 方法字符串 ToS​​tring()
    CourseInstanceID NoteProperty string CourseInstanceID=PGDDA_353650876
    实例 NoteProperty Selected.System.Management.Automation.PSCustomObject Instances=@{CourseCode=PGDDA; 实例代码=PGDSP;会话=2014;配额=999;实例=; CourseInstanceID=PGDD...
    模块 NoteProperty Object[] Modules=System.Object[]
    角色 NoteProperty Object[] Roles=System.Object[]
    

谢谢 - 我不能在这里分享 XML 文档,但我会从我的具体示例转移到一般示例。

假设我们有许多以下 XML 文档

<catalog>
   <book id="bk101">
      <author>Gambardella, Matthew</author>
      <author>Tiny Tim</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>$44.95</price>
      <price>€40.50</price>
      <price>£35.99</price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications with XML.</description>
      <TableOfContents>
      <chapter Title = "Introduction" Number = "1" Page = "1"></chapter>
      <chapter Title = "XSD" Number = "2" Page = "14"></chapter>
      <chapter Title = "XPATH" Number = "3" Page = "27"></chapter>
      <chapter Title = "XQUERY" Number = "4" Page = "42"></chapter>
      <chapter Title = "XHTML" Number = "5" Page = "58"></chapter>
      <chapter Title = "XSLT" Number = "6" Page = "75"></chapter>
      </TableOfContents>
   </book> 
</catalog>

我想把它转换成这种格式的表格(图片抱歉)

样品表

我还应该提到,一个文档中可能有很多书节点,所以我想要每本书都有一个表格。

4

1 回答 1

1

好的,已经一个多星期了,但我不在办公室。我想我有办法解决你的问题。我编写了一个递归调用自身来展平 XML 数组的函数。由于数组可能包含具有相同名称的列,因此我将它们展平为 Array1.Column1、Array1.Column2 的命名上下文。为了更好地参考,在您的示例中,chapter数组将被展平为 columns chapter.Titlechapter.Numberchapter.Page

因此,首先我加载您的示例 XML:

[xml]$Data = @'
<catalog>
    <book id="bk101">
        <author>Gambardella, Matthew</author>
        <author>Tiny Tim</author>
        <title>XML Developer's Guide</title>
        <genre>Computer</genre>
        <price>$44.95</price>
        <price>€40.50</price>
        <price>£35.99</price>
        <publish_date>2000-10-01</publish_date>
        <description>An in-depth look at creating applications with XML.</description>
        <TableOfContents>
        <chapter Title = "Introduction" Number = "1" Page = "1"></chapter>
        <chapter Title = "XSD" Number = "2" Page = "14"></chapter>
        <chapter Title = "XPATH" Number = "3" Page = "27"></chapter>
        <chapter Title = "XQUERY" Number = "4" Page = "42"></chapter>
        <chapter Title = "XHTML" Number = "5" Page = "58"></chapter>
        <chapter Title = "XSLT" Number = "6" Page = "75"></chapter>
        </TableOfContents>
    </book> 
</catalog>
'@

现在我可以使用它了,我创建了一个函数,它可以递归地展平任何数组,并查看它找到的任何对象以查看它们是否包含数组:

Function Flatten-SubNode([object]$NodeIn){
    $Node = $NodeIn.Clone()
    $XMLExcludes = $Node.psobject.Methods.name|where({$_ -like 'get_*'})|%{$_.Substring(4)}
    [array]$NodeProps = $Node.psobject.properties.name|?{$_ -notin $XMLExcludes}
    $FlattenedNode = New-Object PSObject
    $FlattenedProps = @()
    ForEach($Property in $NodeProps) 
    {
        Switch($Node.$Property){
            {$_ -is [string]} {If($Property -notin $FlattenedProps){Add-Member -InputObject $FlattenedNode -NotePropertyName $Property -NotePropertyValue @();$FlattenedProps += $Property};$FlattenedNode.$Property += $_; continue}
            {$_ -is [array]}  {
                Switch($_){
                    {$_ -is [string]}{[array]$Strings += $_;continue}
                    {$_ -isnot [array]}{
                        $SubItem=$_
                        ForEach($SubProp in ($_.PSObject.Properties.Name|Where{$_ -notin $XMLExcludes})){
                            If("$Property.$SubProp" -notin $FlattenedProps){
                                Add-Member -InputObject $FlattenedNode -NotePropertyName "$Property.$SubProp" -NotePropertyValue @()
                                $FlattenedProps += "$Property.$SubProp"
                            }
                            $FlattenedNode."$Property.$SubProp" += $SubItem.$SubProp
                        }
                        Continue}
                    default {
                        Flatten-SubNode $_|%{
                            $SubItem=$_
                            ForEach($SubProp in ($_.PSObject.Properties.Name|Where{$_ -notin $XMLExcludes})){
                                If("$Property.$SubProp" -notin $FlattenedProps){
                                    Add-Member -InputObject $FlattenedNode -NotePropertyName "$Property.$SubProp" -NotePropertyValue @()
                                    $FlattenedProps += "$Property.$SubProp"
                                }
                                $FlattenedNode."$Property.$SubProp" += $SubItem.$SubProp
                            }
                        }
                    }
                }
                If($Strings){$Node.$Property = $Strings}Else{$Node = $Node | Select * -ExcludeProperty $Property}

            }
            default {
                $SubItem=Flatten-SubNode $_
                ForEach($SubProp in ($SubItem.PSObject.Properties.Name|Where{$_ -notin $XMLExcludes})){
                    If("$Property.$SubProp" -notin $FlattenedProps){
                        Add-Member -InputObject $FlattenedNode -NotePropertyName "$Property.$SubProp" -NotePropertyValue @()
                        $FlattenedProps += "$Property.$SubProp"
                    }
                    $FlattenedNode."$Property.$SubProp" += $SubItem.$SubProp
                }
            }
        }
    }
    $FlattenedNode
}

输出的是单个对象,其属性是任何给定列的记录数组。然后它计算任何给定列有多少记录,并取最大的数字。然后它创建了许多对象,从顶部开始,所有潜在的列都作为属性。第一个总是对每个属性都有一个值。随着它在更多属性中移动,最终将没有值,因为数组已用尽。例如,只有第一个对象会有图书的 ID 值,因为图书只有 1 个 ID,而前 2 个对象将在 Author 列中具有值,所有对象都将在 chapter.Title 中具有值, chapter.Number 和 chapter.Page 属性,因为该数组的记录最多。

ForEach($Book in $Data.catalog.book){
    $FlattenedBook = Flatten-SubNode $Data.catalog.book
    $Rows=$Flattenedbook.psobject.properties.name|%{$FlattenedBook.$_.count}|sort -Descending|Select -first 1
    $Results=For($i=0;$i -le $Rows;$i++){
        $RowObj = New-Object PSObject
        $Flattenedbook.psobject.properties.name|%{
            add-member -InputObject $RowObj -NotePropertyName $_ -NotePropertyValue $Flattenedbook.$_[$i]}
        $RowObj
    }
    $Results | ConvertTo-Html -Property * -as Table -Fragment |Set-Content C:\Temp\$($Book.id).htm
}

我将其设置为根据我的 C:\temp 文件夹中的图书 ID 号输出文件。我认为它运行得很好,因为它输出了一个名为 C:\temp\bk101.htm 的文件,其中只有一个表(运行代码片段以查看结果表):

<table>
<colgroup><col/><col/><col/><col/><col/><col/><col/><col/><col/><col/></colgroup>
<tr><th>id</th><th>author</th><th>title</th><th>genre</th><th>price</th><th>publish_date</th><th>description</th><th>TableOfContents.chapter.Title</th><th>TableOfContents.chapter.Number</th><th>TableOfContents.chapter.Page</th></tr>
<tr><td>bk101</td><td>Gambardella, Matthew</td><td>XML Developer&#39;s Guide</td><td>Computer</td><td>$44.95</td><td>2000-10-01</td><td>An in-depth look at creating applications with XML.</td><td>Introduction</td><td>1</td><td>1</td></tr>
<tr><td></td><td>Tiny Tim</td><td></td><td></td><td>Ç40.50</td><td></td><td></td><td>XSD</td><td>2</td><td>14</td></tr>
<tr><td></td><td></td><td></td><td></td><td>&#163;35.99</td><td></td><td></td><td>XPATH</td><td>3</td><td>27</td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>XQUERY</td><td>4</td><td>42</td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>XHTML</td><td>5</td><td>58</td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>XSLT</td><td>6</td><td>75</td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
</table>

于 2017-04-13T17:35:00.877 回答