将自定义对象数组转换为 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.Title
、chapter.Number
和 chapter.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'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>£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>
我目前正在尝试将一些 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.Title
、chapter.Number
和 chapter.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'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>£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>