I like my XML pretty. There's no format-xml cmdlet or tidy-xml in PowerShell, so here's my first try:
我很喜欢XML。 在PowerShell中没有format-xml cmdlet或tidy-xml,因此这是我的第一次尝试:
#Name me tidy-xml.ps1
# - this crap written by Scott Hanselman
[System.Reflection.Assembly]::LoadWithPartialName("System.Xml") > $null
$PRIVATE:tempString = ""
if ($args[0].GetType().Name -eq "XmlDocument")
{
$PRIVATE:tempString = $args[0].get_outerXml()
}
if ($args[0].GetType().Name -eq "String")
{
$PRIVATE:tempString = $args[0]
}
$r = new-object System.Xml.XmlTextReader(new-object System.IO.StringReader($PRIVATE:tempString))
$sw = new-object System.IO.StringWriter
$w = new-object System.Xml.XmlTextWriter($sw)
$w.Formatting = [System.Xml.Formatting]::Indented
do { $w.WriteNode($r, $false) } while ($r.Read())
$w.Close()
$r.Close()
$sw.ToString()#命名我tidy-xml.ps1 #-这是Scott Hanselman写的废话[System.Reflection.Assembly] :: LoadWithPartialName(“ System.Xml”)> $ null $ PRIVATE:tempString =“” 如果($ args [0] .GetType()。Name -eq“ XmlDocument”) { $ PRIVATE:tempString = $ args [0] .get_outerXml() } 如果($ args [0] .GetType()。Name -eq“ String”) { $ PRIVATE:tempString = $ args [0] } $ r =新对象System.Xml.XmlTextReader(新对象System.IO.StringReader($ PRIVATE:tempString)) $ sw =新对象System.IO.StringWriter $ w =新对象System.Xml.XmlTextWriter($ sw) $ w.Formatting = [System.Xml.Formatting] :: Indented 做{$ w.WriteNode($ r,$ false)}而($ r.Read()) $ w.Close() $ r.Close() $ sw.ToString()
Sometimes XML is thought of as strings and sometimes as [xml] in PowerShell. This script will take either a string or [xml] but will always return a string. (e.g. It's on you to do the final [xml] cast because if you did, the tidying is moot). For example:
在PowerShell中,有时XML被视为字符串,有时被视为[xml]。 该脚本将使用字符串或[xml],但将始终返回字符串。 (例如,您要执行最终的[xml]强制转换,因为如果这样做,那么整理是没有意义的)。 例如:
PS> $a = "<foo><bar>asdasd</bar></foo>"
PS> ./tidy-xml $a
<foo>
<bar>asdasd</bar>
</foo>
PS> $b = [xml]"<foo><bar>asdasd</bar></foo>"
PS> ./tidy-xml $b
<foo>
<bar>asdasd</bar>
</foo>PS> $ a =“ <foo> <bar> asdasd </ bar> </ foo>” PS> ./tidy-xml $ a <foo> <bar> asdasd </ bar> </ foo> PS> $ b = [xml]“ <foo> <bar> asdasd </ bar> </ foo>” PS> ./tidy-xml $ b <foo> <bar> asdasd </ bar> </ foo>
I wanted to make it so I could do these scenarios. Thoughts? Remember that I need to normalize to a string for the StringReader constructor.
我想做到这一点,所以我可以做这些情况。 有什么想法吗? 请记住,我需要将StringReader构造函数标准化为字符串。
#couldn't because it returned an Object[] of strings and it got sloppy fast
get-content foo.xml | tidy-xml#不能,因为它返回了字符串的Object [],并且变得很草率get-content foo.xml | 整洁的xml
#couldn't because it (oddly) returned an ArrayList of strings and it got sloppy fast
get-content foo.xml -ov c
tidy-xml $c#不能,因为它(奇怪地)返回了一个ArrayList字符串,并且变得草率地获取内容foo.xml -ov c 整洁的xml $ c
Enjoy (or improve!)
享受(或改善!)
UPDATE: Here's a better version that includes a number of best-practices changes as well as the support for taking IN objects from the pipeline (like I wanted originally):
更新:这是一个更好的版本,其中包括许多最佳实践更改以及对从管道中获取IN对象的支持(如我最初想要的那样):
#The following cases work
#
#PS>$a
#<foo><bar>this is A</bar></foo
#PS>$b.get_OuterXml()
#<foo><bar>this is B</bar></foo
#PS>Get-Content foo.xml
#<foo>
# <bar>this is C</bar>
#</foo>
#
#Now try the following.
#PS>sal ti tidy-xml
#PS>$a | ti
#PS>$b | ti
#PS>$c | ti
#PS>ti $a
#PS>ti $b
#PS>ti $c
#PS>$a, $b | ti
#PS>$a, $c | ti
#PS>$c, $b | ti
#PS>$a, $b, $c | ti
#
#What doesn't work here is when you pass a multiple parameter input as follows:
#tidy-xml $a, $b # doesn't work
#
#Uhm, i think i would have to change my logic "completely" to actually get that to work...
#(after refactoring "process" block...)
#
#Name me tidy-xml.ps1
# - some of this crap written by Scott Hanselman
function Tidy-Xml {
begin {
$private:str = ""
# recursively concatenate strings from passed-in arrays of schmutz
# not sure how to improve this...
function ConcatString ([object[]] $szArray) {
# return string
$private:rStr = ""#以下情况有效# #PS> $ a #<foo> <bar>这是A </ bar> </ foo #PS> $ b.get_OuterXml() #<foo> <bar>这是B </ bar> </ foo #PS>获取内容foo.xml #<foo> #<bar>这是C </ bar> #</ foo> # #现在尝试以下方法。 #PS> sal ti tidy-xml #PS> $ a | ti #PS> $ b | ti #PS> $ c | ti #PS> ti $ a #PS> ti $ b #PS> ti $ c #PS> $ a,$ b | ti #PS> $ a,$ c | ti #PS> $ c,$ b | ti #PS> $ a,$ b,$ c | ti # #此处不起作用是当您按如下方式传递多参数输入时: #tidy-xml $ a,$ b#不起作用# #嗯,我认为我必须“完全”改变我的逻辑才能真正使之工作... #(重构“ process”块后...) # #命名我tidy-xml.ps1 #-Scott Hanselman写的一些废话功能Tidy-Xml { 开始 { $ private:str =“” #从schmutz的传入数组中递归连接字符串#不确定如何改善此问题... 函数ConcatString([object []] $ szArray){ #返回字符串$ private:rStr =“”
# Recursively call itself, if a string is also of array or a collection type
foreach ($private:sz in $szArray) {
if (($private:sz.GetType().IsArray) -or `
($private:sz -is [System.Collections.IList])) {
$private:rStr += ConcatString($private:sz)
}
elseif ($private:sz -is [xml]) {
$private:rStr += $private:sz.Get_OuterXml()
}
else {
$private:rStr += $private:sz
}
}
return $private:rStr;
}
# Original "Tidy-Xml" portion
function FormatXmlString ($arg) {
# ignore parse errors
trap { continue; }
# out-null hides output of the assembly load
[System.Reflection.Assembly]::LoadWithPartialName("System.Xml") | out-null#如果字符串也是数组或集合类型,则递归调用自身foreach($ szArray中的$ private:sz){ 如果(($ private:sz.GetType()。IsArray)-或` ($ private:sz -is [System.Collections.IList])){ $ private:rStr + = ConcatString($ private:sz) } elseif($ private:sz -is [xml]){ $ private:rStr + = $ private:sz.Get_OuterXml() } 其他{ $ private:rStr + = $ private:sz } } 返回$ private:rStr; } #原始的“ Tidy-Xml”部分函数FormatXmlString($ arg){ #忽略解析错误陷阱{继续; } #out-null隐藏汇编负载的输出[System.Reflection.Assembly] :: LoadWithPartialName(“ System.Xml”)| 零
$PRIVATE:tempString = ""
if ($arg -is [xml]){
$PRIVATE:tempString = $arg.get_outerXml()
}
if ($arg -is [string]){
$PRIVATE:tempString = $arg
}$ PRIVATE:tempString =“” 如果($ arg -is [xml]){ $ PRIVATE:tempString = $ arg.get_outerXml() } 如果($ arg -is [string]){ $ PRIVATE:tempString = $ arg }
# the ` tick mark is a line-continuation char
$r = new-object System.Xml.XmlTextReader(`
new-object System.IO.StringReader($PRIVATE:tempString))
$sw = new-object System.IO.StringWriter
$w = new-object System.Xml.XmlTextWriter($sw)
$w.Formatting = [System.Xml.Formatting]::Indented#`勾号是行继续符$ r =新对象System.Xml.XmlTextReader(` 新对象System.IO.StringReader($ PRIVATE:tempString)) $ sw =新对象System.IO.StringWriter $ w =新对象System.Xml.XmlTextWriter($ sw) $ w.Formatting = [System.Xml.Formatting] :: Indented
do { $w.WriteNode($r, $false) } while ($r.Read())
$w.Close()
$r.Close()
$sw.ToString()
}
}
process {
# For non-xml strings or types, they will be buffered and will be
# taken care of in "end" block
# this checks for objects that have been "pipe'd" in.
if ($_) {
# check if whatever we have appended is a valid XML or not
$private:xmlStr = ($private:str + $_) -as [xml]
if ($private:xmlStr -ne $null) {
FormatXmlString([xml]$private:xmlStr)
# clear the string not to be handled in "end" block
$private:str = $null
} else {
if ($_ -is [string]) {
$private:str += $_
} elseif ($_ -is [xml]) {
FormatXmlString($_)
}
# for an array or a collection type,
elseif ($_.Count) {
# iterate each item in the collection and append
foreach ($i in $_) {
$private:line += $i
}
$private:str += $private:line
}
}
}
}做{$ w.WriteNode($ r,$ false)}而($ r.Read()) $ w.Close() $ r.Close() $ sw.ToString() } } 流程{ #对于非xml字符串或类型,它们将被缓冲并被#在“ end”块中处理#这会检查“管道”进入的对象。 如果($ _){ #检查我们附加的内容是否是有效的XML $ private:xmlStr =($ private:str + $ _)-as [xml] 如果($ private:xmlStr -ne $ null){ FormatXmlString([xml] $ private:xmlStr) #清除“ end”块中不处理的字符串$ private:str = $ null }其他{ if($ _ -is [string]){ $ private:str + = $ _ } elseif($ _ -is [xml]){ FormatXmlString($ _) } #用于数组或集合类型, elseif($ _。Count){ #迭代集合中的每个项目并追加foreach($ i in $ _){ $私人:线+ = $ i } $ private:str + = $ private:line } } } }
end {
if ([string]::IsNullOrEmpty($private:str)) {
$private:szXml = $(ConcatString($args)) -as [xml]
if (! [string]::IsNullOrEmpty($private:szXml)) {
FormatXmlString([xml]$private:szXml)
}
} else {
FormatXmlString([xml]$private:str)
}
}
}结束 { 如果([[string] :: IsNullOrEmpty($ private:str)){ $ private:szXml = $(ConcatString($ args))-as [xml] 如果(![string] :: IsNullOrEmpty($ private:szXml)){ FormatXmlString([xml] $ private:szXml) } }其他{ FormatXmlString([xml] $ private:str) } } }
Thanks to MonadBlog for the Updates! There's definitely some room for refactoring of the begin/end/process, but it's more funcitonal this way.
感谢MonadBlog的更新! 肯定有一些空间可以重构开始/结束/过程,但是这种方式更有趣。