PowerShell中的Xml Tidy或使用PowerShell缩进格式化Xml

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的更新! 肯定有一些空间可以重构开始/结束/过程,但是这种方式更有趣。

翻译自: https://www.hanselman.com/blog/an-xml-tidy-in-powershell-or-formatting-xml-with-indenting-with-powershell

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值