【问题标题】:How to replace field in XML file using xmllint or xmlstarlet?如何使用 xmllint 或 xmlstarlet 替换 XML 文件中的字段?
【发布时间】:2022-12-30 10:43:26
【问题描述】:

我有以下 xml 文件:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:aut="http://">
   <soapenv:Header>
      <aut:Session>
         <aut:IPAddress>127.0.0.1</aut:IPAddress>
         <aut:SessionToken>true</aut:SessionToken>
         <aut:ApplicationToken>861</aut:ApplicationToken>
      </aut:Session>
   </soapenv:Header>
   <soapenv:Body></soapenv:Body>
</soapenv:Envelope>

替换&lt;aut:SessionToken&gt;true&lt;/aut:SessionToken&gt;的最佳方法是什么 &lt;aut:SessionToken&gt;false&lt;/aut:SessionToken&gt;

这是我正在尝试的:

xmllint --shell file.xml << EOF
cd //*[local-name() = "Header"]/*[local-name() = "Session"]/text()/*[local-name() = "SessionToken"]/text()
set failed
save
EOF

当我尝试将 true 替换为 false 时,由于命名空间而遇到问题。

布, 京东

【问题讨论】:

    标签: xml bash parsing xmlstarlet xmllint


    【解决方案1】:

    在处理 SOAP 信封时,我不会使用 *[local-name() = "…"] 忽略命名空间。相反,使用显式命名空间绑定。

    例如,要切换布尔值

    xmlstarlet edit -N aut="http://" 
        --var T '//aut:Session/aut:SessionToken' 
        -u '$T' -x 'not($T)' file.xml 
    

    -N 之前添加-L / --inplace 以就地编辑文件。

    要读取它的值:

    xmlstarlet select -N aut="http://" 
        -t -v '//aut:Session/aut:SessionToken' -n file.xml
    

    【讨论】:

      【解决方案2】:

      您快到了。你只是在那里有一个额外的 text() 元素。在 xmlstarlet 中,尝试

          xml ed -u '//*[local-name() = "Header"]/*[local-name() = "Session"] 
      //*[local-name() = "SessionToken"]//text()' -v "false" yourfile.xml
      

      【讨论】:

        【解决方案3】:

        您使用 xmllint 的方法与正确的相差不远。只需要添加名称空间处理并在 XPath 表达式中使用名称空间前缀。

        setrootns
        cd //soapenv:Header/aut:Session/aut:SessionToken
        set failed
        save
        

        作为单线:

        echo -e "setrootns
         cd //soapenv:Header/aut:Session/aut:SessionToken
         set failed
         save
         bye" | xmllint --shell test.xml
        

        【讨论】:

        • 这种方法比 //*[local-name()… 更具可读性。 @LMC 但是,您介意解释一下setrootns 的目的吗?因为它似乎是强制性的,因为没有它就无法工作?
        • setrootns 使解析器考虑在根元素中声明的命名空间,因此可以在 xpath 表达式中使用前缀。 local-name() 不需要命名空间,代价是更复杂/难以阅读的表达式。要查看xmllint shell 命令,请运行xmllint --shell any.xml,然后发出help 命令。
        【解决方案4】:

        操作方法:调试 XML 结构并替换节点的值

        由于您可能想用不同的结构和节点更改您自己的 XML 文件,因此可能很难找到正确的语法来更改值。

        以下实践展示了如何以交互模式(即调试)导航通过任何 xml 文件以找到节点(即语法)应该被替换。

        xmllint --shell file.xml        # starts xmllint in interactive mode
        setrootns
        cat                             # shows the complete XML structure
        <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:aut="http://">
           <soapenv:Header>
              <aut:Session>
                 <aut:IPAddress>127.0.0.1</aut:IPAddress>
                 <aut:SessionToken>true</aut:SessionToken>
                 <aut:ApplicationToken>861</aut:ApplicationToken>
              </aut:Session>
           </soapenv:Header>
           <soapenv:Body></soapenv:Body>
        </soapenv:Envelope>
        

        现在您可以通过 XML 树逐步走到所需的节点:

        cd //soapenv:Envelope                               # change to the first level
        soapenv:Envelope >                                  # the prompt changes on success
        cd //soapenv:Envelope/soapenv:Header/aut:Session
        aut:Session >                                       # appropriate prompt change
        cat 
         <aut:Session>
             <aut:IPAddress>127.0.0.1</aut:IPAddress>
             <aut:SessionToken>true</aut:SessionToken>
             <aut:ApplicationToken>861</aut:ApplicationToken>
         </aut:Session>
        

        直接显示某个节点/路径的结构和值(无需事先cd):

        cat //soapenv:Envelope/soapenv:Header/aut:Session
        
        <aut:Session>
             <aut:IPAddress>127.0.0.1</aut:IPAddress>
             <aut:SessionToken>true</aut:SessionToken>
             <aut:ApplicationToken>861</aut:ApplicationToken>
         </aut:Session>
        

        请记住,路径末尾不要有斜杠,因为它找不到节点:

        cat //soapenv:Envelope/soapenv:Header/aut:Session/    # trailing slash throws an error
        
        XPath error : Invalid expression
        //soapenv:Envelope/soapenv:Header/aut:Session/
                                                     ^
        //soapenv:Envelope/soapenv:Header/aut:Session: no such node
        

        假设我们想更改 IP 地址,最好先检查正确的路径:

        cat //soapenv:Envelope/soapenv:Header/aut:Session/aut:IPAddress
        <aut:IPAddress>127.0.0.1</aut:IPAddress>
        

        或者只是获取节点的值:

        cat //soapenv:Envelope/soapenv:Header/aut:Session/aut:IPAddress/text()
        127.0.0.1
        

        先改成合适的路径:

         cd //soapenv:Envelope/soapenv:Header/aut:Session/aut:IPAddress
         aut:IPAddress > cat text()         # alternative way to check the value
         127.0.0.1
         aut:IPAddress > set 1.1.1.1        # change the value
         aut:IPAddress > cat text()         # crosscheck the changed value
         1.1.1.1
         aut:IPAddress > save               # save changes to file
         aut:IPAddress > save backup.xml    # save changes to another file
         aut:IPAddress > quit
        

        help 在交互模式下将显示有关命令的更多详细信息。 https://gnome.pages.gitlab.gnome.org/libxml2/xmllint.html#shell 还提供了有关 shell 命令的详细信息。

        一旦确定了节点的正确路径(应该更改),您就可以参考上面的@LMCs 一行来动态更改 XML 文件。

        【讨论】:

          猜你喜欢
          • 2018-07-13
          • 2019-01-09
          • 2015-10-28
          • 1970-01-01
          • 2018-03-05
          • 2023-03-23
          • 2022-12-22
          • 2020-10-21
          • 1970-01-01
          相关资源
          最近更新 更多