我正在尋找一個 Powershell 函式來將 XML 轉換為最終可以匯出為 JSON 的 PsCustomObject。為此,我創建了這個小的 XML 測驗物件:
[xml]$Xml = @"
<Action name="Test" id="1">
<Text>sample</Text>
<sub name="s1" id="2" />
<sub name="s2" id="3" />
<end details="no" />
</Action>
"@
這給了我一個 XML DocumentElement,我最終需要將其轉換為與此呼叫中的物件相同的物件:
$Json = convertfrom-json @"
{
"Action": {
"name": "Test", "id": "1", "Text": "sample",
"sub": [
{"name": "s1","id": "2"},
{"name": "s2","id": "3"}
],
"End": {"details": "no"}
}
}
"@
有什么聰明的方法可以完成這項作業嗎?我在這里從類似的問題中測驗了多個功能,但沒有真正按預期作業。
uj5u.com熱心網友回復:
由于含糊不清,沒有將 XML 轉換為 JSON 的標準方法。因此,您確實必須推出自己的函式,以匹配所需輸出的方式解釋 XML。
這是一個通用的解決方案:
Function ConvertFrom-MyXml( [xml.XmlNode] $node ) {
# Create an ordered hashtable
$ht = [ordered] @{}
# Copy the XML attributes to the hashtable
$node.Attributes.ForEach{ $ht[ $_.Name ] = $_.Value }
$node.ChildNodes.ForEach{
if( $_.FirstChild -is [xml.XmlText] ) {
# Add content of XML text node
Add-DictionaryArrayItem -Dict $ht -Key $_.LocalName -Value $_.FirstChild.InnerText
}
elseif( $_ -is [xml.XmlElement] ) {
# Add nested hashtable for the XML child elements (recursion)
Add-DictionaryArrayItem -Dict $ht -Key $_.LocalName -Value (ConvertFrom-MyXml $_)
}
}
$ht # Output
}
Function Add-DictionaryArrayItem( $Dict, $Key, $Value ) {
if( $Dict.Contains( $Key ) ) {
$curValue = $Dict[ $Key ]
# If existing value is not already a list...
if( $curValue -isnot [Collections.Generic.List[object]] ) {
# ...turn it into a list.
$curValue = [Collections.Generic.List[object]] @($curValue)
$Dict[ $Key ] = $curValue
}
# Add next value to the array. This updates the array in the hashtable,
# because $curValue is a reference.
$curValue.Add( $Value )
}
else {
# Key doesn't exist in the hashtable yet, so simply add it.
$Dict[ $Key ] = $Value
}
}
[xml]$Xml = @"
<Action name="Test" id="1">
<Text>sample</Text>
<sub name="s1" id="2" />
<sub name="s2" id="3" />
<end details="no" />
</Action>
"@
ConvertFrom-MyXml $Xml | ConvertTo-Json -Depth 100
輸出:
{
"Action": {
"name": "Test",
"id": "1",
"Text": "sample",
"sub": [
{
"name": "s1",
"id": "2"
},
{
"name": "s2",
"id": "3"
}
],
"end": {
"details": "no"
}
}
}
- 函式
ConvertFrom-MyXml輸出一個有序的哈希表。也無需轉換為PSCustomObjectasConvertFrom-Json適用于哈希表。所以我們可以讓代碼更簡單。 ConvertFrom-MyXml回圈遍歷給定 XML 節點的屬性和元素(遞回)。Add-DictionaryArrayItem如果哈希表中已經存在鍵,它會呼叫輔助函式來創建一個陣列。實際上,這不是一個原始的、固定大小的陣列(如@(1,2,3)創建),而是一個動態調整大小List的陣列,它的行為與陣列非常相似,但在添加許多元素時效率更高。- 請注意,單個
sub元素不會變成陣列。如果某些元素應該始終轉換為陣列,則必須將某種模式傳遞給函式(例如元素名稱串列)或將元資料添加到 XML 本身。
正如 OP 所建議的,這是代碼的替代版本,它僅包含一個函式:
Function ConvertFrom-MyXml( [xml.XmlNode] $node ) {
$ht = [ordered] @{}
$node.Attributes.ForEach{ $ht[ $_.Name ] = $_.Value }
foreach( $child in $node.ChildNodes ) {
$key = $child.LocalName
$value = if( $child.FirstChild -is [xml.XmlText] ) {
$child.FirstChild.InnerText
} elseif( $child -is [xml.XmlElement] ) {
ConvertFrom-MyXml $child
} else {
continue
}
if( $ht.Contains( $Key ) ) {
$curValue = $ht[ $Key ]
if( $curValue -isnot [Collections.Generic.List[object]] ) {
$curValue = [Collections.Generic.List[object]] @($curValue)
$ht[ $Key ] = $curValue
}
$curValue.Add( $Value )
}
else {
$ht[ $Key ] = $Value
}
}
$ht # Output
}
uj5u.com熱心網友回復:
可能不是你正在尋找的東西,但我個人會用類來做到這一點:
class Sub {
[string] $Name
[Int] $Id
Sub([string] $Name, [int] $Id) {
$this.Name = $Name
$this.Id = $Id
}
}
# Windows PowerShell will not like it named End :)
class End2 {
[string] $Details
End2 ([string] $Details) {
$this.Details = $Details
}
}
class Action {
[string] $Name
[int] $Id
[string] $Text
[Sub[]] $Sub
[End2] $End
Action () { }
Action ([string] $Name, [int] $Id, [string] $Text, [object[]] $Sub, [End2] $End) {
$this.Name = $Name
$this.Id = $Id
$this.Text = $Text
$this.Sub = @( $Sub )
$this.End = $End
}
[string] ToJson() {
return @{ Action = $this } | ConvertTo-Json -Depth 99
}
}
Action現在您可以像這樣實體化您的類并將其轉換為 Json :
[Action]::new(
'Test', 1, 'Sample',
@(
[Sub]::new('s1', 2)
[Sub]::new('s2', 3)
),
'No'
).ToJson()
或者像這樣:
([Action]@{
Name = 'Test'
Id = 1
Text = 'Sample'
Sub = @(
[Sub]::new('s1', 2)
[Sub]::new('s2', 3)
)
End = 'No'
}).ToJson()
兩者都會輸出以下 Json:
{
"Action": {
"Name": "Test",
"Id": 1,
"Text": "Sample",
"Sub": [
{
"Name": "s1",
"Id": 2
},
{
"Name": "s2",
"Id": 3
}
],
"End": {
"Details": "No"
}
}
}
uj5u.com熱心網友回復:
看看這可能會有所幫助
class sub {
[string] $name;
[int] $id;
}
class end {
[string] $details;
}
class Action {
[string] $Text;
[sub] $sub1;
[sub] $sub2;
[end] $end;
[string] $name;
[int] $id;
}
<#
<Action name="Test" id="1">
<Text>sample</Text>
<sub name="s1" id="2" />
<sub name="s2" id="3" />
<end details="no" />
</Action>
#>
$firstitem = [Action]@{
text = 'sample';
name = "test";
id = "1";
sub1=@{
name = "s1";
id = "2";}
sub2 = @{
name = "s2";
id = "3";}
end = @{
details = "no";}
}
$firstitem | ConvertTo-Json
<#
Output =
{
"Text": "sample",
"sub1": {
"name": "s1",
"id": 2
},
"sub2": {
"name": "s2",
"id": 3
},
"end": {
"details": "no"
},
"name": "test",
"id": 1
}
#>
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/495837.html
