zoukankan      html  css  js  c++  java
  • PowerShell笔记

    本系列是一个重新学习PowerShell的笔记,内容引用自PowerShell中文博客

    XML是”可扩展标记语言“的缩写,是一种对于任意结构化的信息的可描述性语言。过去处理XML还是相当麻烦的,但是现在PowerShell中,对XML有了非常优秀的支持。通过它的帮助,你既可以非常容易的在XML中包装数据,也可以非常舒服的访问已有的XML文件。

    XML 结构

    XML使用标签来唯一标识信息片段,一个标签像网站中的HTML文档使用的一样,是一对尖括号。通常,一条信息被一个起始和结束标记所分割。结束标记前面使用“/”,其结果谓之结点,在下面的例子就应当叫做Name结点。

    <Name>Tobias Weltner</Name>
    

    另外,结点拥有它自身相关信息的属性(attributes)。这些信息位于开始标签。

    <staff branch="Hanover" Type="sales">...</staff>
    

    如果一个结点为空,它的开始结点和结束结点可以折叠起来。结束符号“/”指向标签结束。例如,在Hanover的子公司没有任何员工从事销售工作,那这个标签可以像这样描述。

    <staff branch="Hanover" Type="sales"/>
    

    通常,如果一个标签不空,包含更多信息,这些信息应当包含在标签中。这就允许按照你喜欢的深度产生信息结构。下面XML结构描述Hanover子公司销售部门工作的两位员工。

    <staff branch="Hanover" Type="sales">
        <employee>
            <Name>Tobias Weltner</Name>
            <function>management</function>
            <age>39</age>
        </employee>
        <employee>
            <Name>Cofi Heidecke</Name>
            <function>security</function>
            <age>4</age>
        </employee>
    </staff>
    

    为了让XML文件被识别,通常在它们的开始有一个非常简单类似下面例子中的一个头声明。

    <?xml version="1.0" ?>
    

    头声明声明了紧跟其后的XML符合1.0 版本规范。被称为”schema”的东西也可以在这里被指定。具体来说,Schema有个XSD文件的形式,它用来描述XML文件结构应当遵循确定的规范。在上一个例子中,Schema可能会指定必须包含“staff”结点作为员工的信息,进而指定多个命名为“staff”的子结点为必须的。Schema也可以指定相关的信息,例如每个员工的名称和定义他们具体的职能。

    因为XML文件有纯文本构成,你可以使用编辑器创建他们,也可以直接使用PowerShell。让我们将前面定义的员工信息保存为一个XML文件:

    
    PS C:PowerShell> $xml = @'
    >> <?xml version="1.0" standalone="yes"?>
    >> <staff branch="Hanover" Type="sales">
    >> <employee>
    >> <Name>Tobias Weltner</Name>
    >> <function>management</function>
    >> <age>39</age>
    >> </employee>
    >> <employee>
    >> <Name>Cofi Heidecke</Name>
    >> <function>security</function>
    >> <age>4</age>
    >> </employee>
    >> </staff>
    >> '@ | Out-File employee.xml                                                                                           PS C:PowerShell> ls
    
    
        Directory: C:PowerShell
    
    
    Mode                LastWriteTime         Length Name
    ----                -------------         ------ ----
    -a----        2021/9/22     11:16            556 employee.xml
    

    注意:XML文件大小写敏感的!

    加载和处理XML文件

    访问Xml

    如果你想将XML文件按照实际的XML来处理,而不是纯文本。文件的内容必须转换成XML类型。类型转换在第六章已经提到,只须一行。

    PS C:PowerShell> $xmldata = [xml](Get-Content employee.xml)                                                            PS C:PowerShell> $xmldata                                                                                              
    xml                            staff
    ---                            -----
    version="1.0" standalone="yes" staff
    

    然而,转换只会在指定的xml文本合法并不包含解析错误时有效。当你尝试转换的xml文件结构不合法,会报错。
    用来描述XML的结构和信息现在被存放在变量$xmldata。从现在开始,获取一小段信息将会变得非常容易,因为XML对象将每个结点转换成了属性。你可以像这样获取员工信息:

    PS C:PowerShell> $xmldata.staff.employee                                                                               
    Name           function   age
    ----           --------   ---
    Tobias Weltner management 39
    Cofi Heidecke  security   4
    

    访问和更新单个结点

    如果一个结点在xml中是唯一的,你可以像前面的例子一样输入一个句号来访问它。然而,多数情况下XML文档包含了许多类似的结点(被称为兄弟结点),像前面最后一个例子中一样,包含了多个独立的员工。比如,你可以使用管道获得特定的员工,然后来更新它的数据。

    PS C:PowerShell> $xmldata.staff.employee |
    >> Where-Object { $_.Name -match "Tobias Weltner" }                                                                     
    Name           function   age
    ----           --------   ---
    Tobias Weltner management 39
    
    PS C:PowerShell> $employee = $xmldata.staff.employee |
    >> Where-Object { $_.Name -match "Tobias Weltner" }                                                                     PS C:PowerShell> $employee.function = "vacation"                                                                       PS C:PowerShell> $xmldata.staff.employee | ft -autosize                                                                
    Name           function age
    ----           -------- ---
    Tobias Weltner vacation 39
    Cofi Heidecke  security 4
    

    使用SelectNodes()来选择Nodes

    SelectNodes()方法是Xpath查询语言支持的方法,也允许你选择结点。XPath指的是一个结点‘路径名称’:

    PS C:PowerShell> $xmldata = [xml](Get-Content employee.xml)                                                            PS C:PowerShell> $xmldata.SelectNodes("staff/employee")                                                                
    Name           function   age
    ----           --------   ---
    Tobias Weltner management 39
    Cofi Heidecke  security   4
    

    结果看起来像前面直接通过属性访问一样,但是XPath支持在方括号中使用通配符访问。
    下面的语句只会返回第一个员工结点。

    PS C:PowerShell> $xmldata.SelectNodes("staff/employee[1]")                                                             
    Name           function   age
    ----           --------   ---
    Tobias Weltner management 39
    

    如果你想,你还可以获取一个年龄小于18岁的员工列表:

    
    PS C:PowerShell> $xmldata.SelectNodes("staff/employee[age<18]")                                                        
    Name          function age
    ----          -------- ---
    Cofi Heidecke security 4
    

    类似的方式,查询语言也支持获取列表中的最后一位员工信息,所以也可以指定位置:

    PS C:PowerShell> $xmldata.SelectNodes("staff/employee[last()]")                                                        
    Name          function age
    ----          -------- ---
    Cofi Heidecke security 4
    
    
    PS C:PowerShell> $xmldata.SelectNodes("staff/employee[position()>1]")                                                  
    Name          function age
    ----          -------- ---
    Cofi Heidecke security 4
    

    或者,你可以使用所谓的XpathNavigator,从中获取许多从XML文本的类型转换。

    # 创建一个 XML定位:
    PS C:PowerShell> $xpath = [System.XML.XPath.XPathDocument]`
    >> [System.IO.TextReader][System.IO.StringReader]`
    >> (Get-Content employee.xml | out-string)                                                                              PS C:PowerShell> $navigator = $xpath.CreateNavigator()
    
    # 输出Hanover子公司的最后一位员工
    PS C:PowerShell> $query = "/staff[@branch='Hanover']/employee[last()]/Name"                                            PS C:PowerShell> $navigator.Select($query) | Format-Table Value                                                        
    Value
    -----
    Cofi Heidecke
    
    # 输出Hanover子公司的除了Tobias Weltner之外的所有员工,
    PS C:PowerShell> $query = "/staff[@branch='Hanover']/employee[Name!='Tobias Weltner']"                                                                                                           PS C:PowerShell> $navigator.Select($query) | Format-Table Value                                                        
    Value
    -----
    Tobias Weltnermanagement39
    Cofi Heideckesecurity4
    

    基于Namespace来SelectNode

    上面使用PowerShell处理xml文档时,用到了一个selectNode。但是有时候按照上面代码执行就是看不到期望的结果。原因可能是因为你的XML文档中多了个命名空间(Namespace)。没有命名空间时,Name就是Name,有了命名空间后,Name=Namespace+Name。

    看下面的例子,有一个XML文档,要求输出“Obj”的结点信息。

    PS C:PowerShell> @"
    >> <Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
    >>   <Obj RefId="0">
    >>     <TN RefId="0">
    >>       <T>Selected.System.IO.FileInfo</T>
    >>       <T>System.Management.Automation.PSCustomObject</T>
    >>       <T>System.Object</T>
    >>     </TN>
    >>     <MS>
    >>       <S N="Name">test.txt</S>
    >>       <I64 N="Length">143</I64>
    >>       <DT N="CreationTime">2013-12-01T20:05:22.5568032+08:00</DT>
    >>     </MS>
    >>   </Obj>
    >> </Objs>
    >> "@ | Out-File namespacexml.xml                                                                                       PS C:PowerShell> ls                                                                                                    
    
        Directory: C:PowerShell
    
    
    Mode                LastWriteTime         Length Name
    ----                -------------         ------ ----
    -a----        2021/9/22     11:50            412 employee.xml
    -a----        2021/9/16     13:55            812 Error.txt
    -a----        2021/9/22     11:59            840 namespacexml.xml
    

    如果直接使用SelectNodes方法就会打印下面的信息

    PS C:PowerShell> $xmldata = [xml](Get-Content namespacexml.xml)
    PS C:PowerShell> $xml.DocumentElement.SelectNodes("/Objs/Obj")
    At line:1 char:45
    + $xml.DocumentElement.SelectNodes("/Objs/Obj")
    +                                             ~
    Missing ')' in method call.
    At line:1 char:45
    + $xml.DocumentElement.SelectNodes("/Objs/Obj")
    +                                             ~
    Unexpected token ')' in expression or statement.
        + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
        + FullyQualifiedErrorId : MissingEndParenthesisInMethodCall
    

    此时就需要加入名命空间引用

    PS C:PowerShell> $ns= new-object System.Xml.XmlNamespaceManager $xmldata.NameTable                                     PS C:PowerShell> $ns.AddNamespace("myNS", $xmldata.DocumentElement.NamespaceURI)                                       PS C:PowerShell> $xmldata.DocumentElement.SelectNodes("//myNS:Objs//myNS:Obj",$ns)                                     
    RefId TN MS
    ----- -- --
    0     TN MS
    

    但是我一般不用XML中的SelectNodes,PowerShell中有更方便的方法,请看:

    PS C:PowerShell> $xmldata.Objs.Obj                                                                                     
    RefId TN MS
    ----- -- --
    0     TN MS
    

    访问属性

    属性是定义在一个XML标签中的信息,如果你想查看结点的属性,可以使用get_Attributes()方法:

    PS C:PowerShell> $xmldata.staff.get_Attributes()                                                                       
    #text
    -----
    Hanover
    sales
    

    使用GetAttribute()方法来查询一个特定的属性:

    PS C:PowerShell> $xmldata.staff.GetAttribute("branch")                                                                 Hanover
    

    使用SetAttribute()方法来指定新的属性,或者更新(重写)已有的属性。

    PS C:PowerShell> $xmldata.staff.SetAttribute("branch", "New York")                                                     PS C:PowerShell> $xmldata.staff.GetAttribute("branch")                                                                 New York
    

    添加新结点

    如果你想在员工结点列表中添加新的员工。首先,使用CreateElement()创建一个员工元素,然后定制员工的内部结构。最后,就可以在XML结构中你期望的位置插入这个元素。

    PS C:PowerShell> # 加载XML文本文件:                                                                                   
    PS C:PowerShell> $xmldata = [xml](Get-Content employee.xml)                                                            PS C:PowerShell> # 创建新的结点:                                                                                      
    PS C:PowerShell> $newemployee = $xmldata.CreateElement("employee")                                                     PS C:PowerShell> $newemployee.set_InnerXML("<Name>Bernd Seiler</Name><function>expert</function>")                                                              PS C:PowerShell> # 插入新结点:                                                                                        
    PS C:PowerShell> $xmldata.staff.AppendChild($newemployee)                                                              
    Name         function
    ----         --------
    Bernd Seiler expert
    
    
    PS C:PowerShell> # 验证结果:                                                                                           PS C:PowerShell> $xmldata.staff.employee                                                                               
    Name           function   age
    ----           --------   ---
    Tobias Weltner management 39
    Cofi Heidecke  security   4
    Bernd Seiler   expert
    
    PS C:PowerShell> # 输出为纯文本:                                                                                      
    PS C:PowerShell> $xmldata.get_InnerXml()                                                                               <?xml version="1.0" standalone="yes"?>
    <staff branch="Hanover" Type="sales">
    <employee><Name>Tobias Weltner</Name><function>management</function><age>39</age></employee><employee><Name>Cofi Heidecke</Name><function>security</function><age>4</age></employee><employee><Name>Bernd Seiler</Name><function>expert</function></employee>
    </staff>
    

    保存XML文件

    PS C:PowerShell>  &{(Get-Location).Path + "employee.xml"}                                                             C:PowerShellemployee.xml
    PS C:PowerShell> $xmldata.Save( ((Get-Location).Path + "employee.xml"))                                               PS C:PowerShell> ls                                                                                                    
    
        Directory: C:PowerShell
    
    
    Mode                LastWriteTime         Length Name
    ----                -------------         ------ ----
    -a----        2021/9/22     11:50            412 employee.xml
    
  • 相关阅读:
    VysorPro助手
    Play 2D games on Pixel running Android Nougat (N7.1.2) with Daydream View VR headset
    Play 2D games on Nexus 6P running Android N7.1.1 with Daydream View VR headset
    Native SBS for Android
    ADB和Fastboot最新版的谷歌官方下载链接
    How do I install Daydream on my phone?
    Daydream Controller手柄数据的解析
    蓝牙BLE传输性能及延迟分析
    VR(虚拟现实)开发资源汇总
    Android(Java)控制GPIO的方法及耗时分析
  • 原文地址:https://www.cnblogs.com/MerLin-LiuNian/p/15319511.html
Copyright © 2011-2022 走看看