【问题标题】:Parse an XML file with Powershell使用 Powershell 解析 XML 文件
【发布时间】:2021-01-02 07:16:29
【问题描述】:

我正在尝试解析一个 xml 文件,但似乎无法提取我想要的部分。该 xml 文件是针对一个自制系统的,我无法控制它的布局。

文件看起来像这样——

$doc = [xml]@'
<?xml version="1.0" encoding="utf-8"?>
<rbacx >
    <namespace namespaceName="Team Name" namespaceShortName="ABC"/>
    <attributeValues>
        <attributeValue id="Role=Administrator">
            <value><![CDATA[Administrator]]></value>
            <attributes>
                <attribute name="Glossary">
                    <attributeValues>
                        <attributeValue><value><![CDATA[Administrator (service accounts)]]></value></attributeValue>
                    </attributeValues>
                </attribute>
            </attributes>
        </attributeValue>
        <attributeValue id="Role=Operator">
            <value><![CDATA[Operator]]></value>
            <attributes>
                <attribute name="Glossary">
                    <attributeValues>
                        <attributeValue><value><![CDATA[Operator (all accounts)]]></value></attributeValue>
                    </attributeValues>
                </attribute>
            </attributes>
        </attributeValue>
    </attributeValues>
    <accounts>
        <account id="FRED">
            <name><![CDATA[FRED@xyz.com]]></name>
            <endPoint>ABC</endPoint>
            <domain>ABC</domain>
            <comments/>
            <attributes>
                <attribute name="AppBoRID">
                    <attributeValues>
                        <attributeValue><value><![CDATA[FRED]]></value></attributeValue>
                    </attributeValues>
                </attribute>
                <attribute name="Role">
                    <attributeValues><attributeValueRef id="Role=Operator"/></attributeValues>
                </attribute>
            </attributes>
        </account>
        <account id="BARNEY">
            <name><![CDATA[BARNEY@xyz.com]]></name>
            <endPoint>ABC</endPoint>
            <domain>ABC</domain>
            <comments/>
            <attributes>
                <attribute name="AppBoRID">
                    <attributeValues>
                        <attributeValue><value><![CDATA[BARNEY]]></value></attributeValue>
                    </attributeValues>
                </attribute>
                <attribute name="Role">
                    <attributeValues><attributeValueRef id="Role=Administrator"/></attributeValues>
                </attribute>
            </attributes>
        </account>
        <account id="NonPeopleID_CC1234">
            <name><![CDATA[WILMA@xyz.com]]></name>
            <endPoint>ABC</endPoint>
            <domain>ABC</domain>
            <comments/>
            <attributes>
                <attribute name="appUserName">
                    <attributeValues>
                        <attributeValue><value><![CDATA[WILMA]]></value></attributeValue>
                    </attributeValues>
                </attribute>
                <attribute name="CostCentre">
                    <attributeValues>
                        <attributeValue><value><![CDATA[1234]]></value></attributeValue>
                    </attributeValues>
                </attribute>
                <attribute name="Bank_Number">
                    <attributeValues>
                        <attributeValue><value><![CDATA[0000]]></value></attributeValue>
                    </attributeValues>
                </attribute>
                <attribute name="Directory">
                    <attributeValues>
                        <attributeValue><value><![CDATA[XYZ]]></value></attributeValue>
                    </attributeValues>
                </attribute>
                <attribute name="Role">
                    <attributeValues><attributeValueRef id="Role=Administrator"/></attributeValues>
                </attribute>
            </attributes>
        </account>
        <account id="NonPeopleID_CC1234">
            <name><![CDATA[BETTY@xyz.com]]></name>
            <endPoint>ABC</endPoint>
            <domain>ABC</domain>
            <comments/>
            <attributes>
                <attribute name="appUserName">
                    <attributeValues>
                        <attributeValue><value><![CDATA[BETTY]]></value></attributeValue>
                    </attributeValues>
                </attribute>
                <attribute name="CostCentre">
                    <attributeValues>
                        <attributeValue><value><![CDATA[1234]]></value></attributeValue>
                    </attributeValues>
                </attribute>
                <attribute name="Bank_Number">
                    <attributeValues>
                        <attributeValue><value><![CDATA[0000]]></value></attributeValue>
                    </attributeValues>
                </attribute>
                <attribute name="Directory">
                    <attributeValues>
                        <attributeValue><value><![CDATA[XYZ]]></value></attributeValue>
                    </attributeValues>
                </attribute>
                <attribute name="Role">
                    <attributeValues><attributeValueRef id="Role=Operator"/></attributeValues>
                </attribute>
            </attributes>
        </account>
    </accounts>
</rbacx>

'@

我想得到这样的输出 –

Name            Role
FRED            Operator
BARNEY          Administrator
WILMA           Administrator
BETTY           Operator

我可以通过这个获得 name@domain –

$Doc.rbacx.accounts.account.name 

where it returns - 

#cdata-section
--------------
FRED@xyz.com  
BARNEY@xyz.com
WILMA@xyz.com 
BETTY@xyz.com  

我可以用这个得到所有的值属性-

$Doc.rbacx.accounts.account.attributes.attribute.attributevalues.attributevalue.value 

where it returns - 

#cdata-section
--------------
FRED          
BARNEY        
WILMA         
1234          
0000          
XYZ           
BETTY         
1234          
0000          
XYZ   

我似乎无法获得与返回的用户关联的角色。我想应该是这样的——

$Doc.rbacx.accounts.account.attributes.attribute.attributevalues.attributevalue.attributeValueRef 

然而这并没有返回任何东西。

对如何在此处获取用户及其相关角色输出有何想法?

【问题讨论】:

    标签: xml powershell parsing


    【解决方案1】:

    一旦您熟悉了 XPath,剩下的就不会太糟糕了。此外,更难的是角色名称是Role=Operator 而不仅仅是Operator。因此,您必须对 attributeValueRef 节点上的属性 id 的值进行字符串拆分。最后你会得到这样的东西。

    编辑:合并运算符仅在 Powershell 7+ 中运行

    可以在here 找到很多针对您的 PowerShell 版本的替代方案。

    $doc.SelectNodes("//accounts/account") | % { [pscustomobject]@{Name = $_.SelectSingleNode('attributes/attribute[@name="appUserName"]//value').'#cdata-section' ?? $_.id; Role = $_.SelectSingleNode('attributes/attribute[@name="Role"]//attributeValueRef/@id').value.Split('=')[1] } }
    

    输出是[PSCustomObject]。运行它会在控制台中显示你的输出,但如果你真的需要它只是一个字符串,你可以通过Out-StringFormat-Table 传递它。

    【讨论】:

    • 刚刚意识到用户的实际姓名位于不同的节点中,这让这更加痛苦。
    • 不幸的是我收到一个错误 - “意外的令牌'??'在表达或陈述中。”正如下一个响应所示,我认为这与我使用 v5.1 相关。
    • 我的错。这是 PowerShell 7。如果你有 PowerShell 5.1,那么你必须将 For-Each 块分成多行,并改用 if/else。
    【解决方案2】:

    Arjabbar 的回答非常棒,除非您使用的是不支持 ?? 语法的 5.1。我确信有一种更清洁的方法来检查,但这会达到你的结果。如果帐户有 appusername,它将使用该用户名,否则将使用 ID。

    $doc.SelectNodes("//accounts/account") | foreach {
        $name = if($appusername = $_.SelectSingleNode('attributes/attribute[@name="appUserName"]//value').'#cdata-section')
        {
            $appusername
        }
        else
        {
            $_.id
        }
        [PSCustomObject]@{
            Name = $name
            Role = $_.SelectSingleNode('attributes/attribute[@name="Role"]//attributeValueRef/@id').value.Split('=') | select -last 1
        }
    }
    
    Name   Role         
    ----   ----         
    FRED   Operator     
    BARNEY Administrator
    WILMA  Administrator
    BETTY  Operator 
    

    【讨论】:

    • 谢谢。这看起来正是我所追求的。
    猜你喜欢
    • 2020-12-30
    • 2020-10-22
    • 2013-08-04
    • 2020-12-30
    • 1970-01-01
    • 2019-09-27
    • 1970-01-01
    相关资源
    最近更新 更多