将自定义对象数组转换为 HTML

Convert array of custom objects to HTML

我目前正在尝试将一些 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 最初来自 normailzed 数据库,因此每个 XML 文档或多或少代表一个 table - 它最终成为 PowerShell 中的多维数组。

$data.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

我可以引用单个数组对象

$data[0].roles | ft

rolesGUID rolesIDNumber roleFirstName  roleSurname
--------- ------------- -------------  -----------
55001420  55001420      R              M
55001414  55001414      S              C
55001234  55001234      C              H
55001342  55001342      O              C
55001414  55001414      S              C
55001342  55001342      O              C
55001445  55001445      M              M
55001422  55001422      A              H
55001001  55001001      P              M
55001079  55001079      V              S
55000770  55000770      A              M
55000906  55000906      M              B

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

例如我的输出 Format-Table:

$data | ft

CourseInstanceID Instances                                                                                                                                                      Modules
---------------- ---------                                                                                                                                                      -------
PGDDA_353650876  @{CourseCode=PGDDA; InstanceCode=PGDSP; session=2014; quota=999; Instances=; CourseInstanceID=PGDDA_353650876; Modules=System.Object[]; Roles=System.Object[]} {@{moduleCode=H...
PGDDA_418403503  @{CourseCode=PGDDA; InstanceCode=PGDSP; session=2015; quota=999; Instances=; CourseInstanceID=PGDDA_418403503; Modules=System.Object[]; Roles=System.Object[]} {@{moduleCode=H...

我已经尝试扩展属性并在整个网络上进行了阅读,因此将不胜感激任何指点。

成员如下:


    $data | gm

       TypeName: System.Management.Automation.PSCustomObject

    Name             MemberType   Definition
    ----             ----------   ----------
    Equals           Method       bool Equals(System.Object obj)
    GetHashCode      Method       int GetHashCode()
    GetType          Method       type GetType()
    ToString         Method       string ToString()
    CourseInstanceID NoteProperty string CourseInstanceID=PGDDA_353650876
    Instances        NoteProperty Selected.System.Management.Automation.PSCustomObject Instances=@{CourseCode=PGDDA; InstanceCode=PGDSP; session=2014; quota=999; Instances=; CourseInstanceID=PGDD...
    Modules          NoteProperty Object[] Modules=System.Object[]
    Roles            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>.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>

我想将其转换成 table 这样的格式(图片抱歉)

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

好的,已经一个多星期了,但我不在办公室。我想我有办法解决你的问题。我写了一个函数,它递归地调用自己来展平你的 XML 数组。由于数组可能包含具有相同名称的列,因此我将它们展平为 Array1.Column1、Array1.Column2 的命名上下文。为了更好地参考,在您的示例中,chapter 数组将展平为 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>.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 值,因为该书只有一个 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(运行 片段以查看生成的 table):

<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>.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>