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

时间:2017-03-27 16:46:41

标签: powershell pscustomobject

我目前正在尝试将一些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文档或多或少代表一个表 - 最终成为一个多维数组在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进行报告 - 但我不知道如何枚举这种类型的结构 - 我应该留下的是一个包含一对多关系的表(是多维数组或锯齿状数组?)有人能给我一些关于如何输出这些类型结构的指针吗?当输出是某种类型的矩阵时,迭代数组或对象是很好的 - 但是当结构是某些列的多行而其他列的单行时我们会使用什么。

例如我的输出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>$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>

我想将此转换为此格式的表格(图片抱歉)

sample table

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

1 个答案:

答案 0 :(得分:0)

好的,所以已经过了一个星期,但我不在办公室。我想我有一个解决你问题的方法。我编写了一个函数,递归调用自身来展平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>$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.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的文件(运行代码片段以查看结果表):

&#13;
&#13;
<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>
&#13;
&#13;
&#13;