.net PowerShell -保存时不保留XML格式

syqv5f0l  于 2023-03-20  发布在  .NET
关注(0)|答案(1)|浏览(164)

我正在PowerShell中编写一个修改XML文件的脚本。我以前没有真正使用过XML,所以我在摸索着完成这个过程。我弄清楚了如何加载、搜索、插入元素和属性以及保存更改。我遇到的问题是当我保存更改时,原始XML文件的格式没有被保留。特别是名称空间行被严重破坏。对于一些附加的上下文,我正在使用位于conf文件夹中的Apache Tomcat web.xml文件。
下面是原始XML文件的一个片段,为了给予您了解原始格式,省略了一些行:

<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  version="4.0">
  

  <!-- ======================== Introduction ============================== -->
  <!-- This document defines default values for *all* web applications      -->
  <!-- loaded into this instance of Tomcat.  As each application is         -->
  <!-- deployed, this file is processed, followed by the                    -->
  <!-- "/WEB-INF/web.xml" deployment descriptor from your own               -->
  <!-- applications.                                                        -->
  <!--                                                                      -->
  <!-- WARNING:  Do not configure application-specific resources here!      -->
  <!-- They should go in the "/WEB-INF/web.xml" file in your application.   -->

  <!-- ================== Built In Servlet Definitions ==================== -->

  <!-- The default servlet for all web applications, that serves static     -->
  <!-- resources.  It processes all requests that are not mapped to other   -->
  <!-- servlets with servlet mappings (defined either here or in your own   -->
  <!-- web.xml file).  This servlet supports the following initialization   -->
  <!-- parameters (default values are in square brackets):                  -->

    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

</web-app>

我尝试了很多方法,但结果都不理想。我想在元素下面插入一些元素并保存更改,保持上面代码片段中显示的原始格式。问题与我正在进行的编辑无关,因为我尝试加载XML文件并立即保存。我发现在保存格式时,格式以某种方式被破坏了。取决于我尝试了什么。
我一直在使用.NET System.Xml.XmlDocument类加载和保存XML文件,还尝试使用XmlWriter和XmlWriterSettings类。
以下是我尝试过的方法和结果。
代码:

$webXml = New-Object System.Xml.XmlDocument
$xmlPath = "C:\path\to\web.xml"
$xmlDoc.Load($xmlPath)
$webXml.Save($xmlPath)

结果:

<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee&#xD;&#xA;                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
  <!-- ======================== Introduction ============================== -->
  <!-- This document defines default values for *all* web applications      -->
  <!-- loaded into this instance of Tomcat.  As each application is         -->
  <!-- deployed, this file is processed, followed by the                    -->
  <!-- "/WEB-INF/web.xml" deployment descriptor from your own               -->
  <!-- applications.                                                        -->
  <!--                                                                      -->
  <!-- WARNING:  Do not configure application-specific resources here!      -->
  <!-- They should go in the "/WEB-INF/web.xml" file in your application.   -->
  <!-- ================== Built In Servlet Definitions ==================== -->
  <!-- The default servlet for all web applications, that serves static     -->
  <!-- resources.  It processes all requests that are not mapped to other   -->
  <!-- servlets with servlet mappings (defined either here or in your own   -->
  <!-- web.xml file).  This servlet supports the following initialization   -->
  <!-- parameters (default values are in square brackets):                  -->
  <servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
      <param-name>debug</param-name>
      <param-value>0</param-value>
    </init-param>
    <init-param>
      <param-name>listings</param-name>
      <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
</web-app>

代码:

$webXml = New-Object System.Xml.XmlDocument
$webXml.PreserveWhitespace = $true
$xmlPath = "C:\path\to\web.xml"
$xmlDoc.Load($xmlPath)
$webXml.Save($xmlPath)

结果:

<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee&#xD;&#xA;                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">

  <!-- ======================== Introduction ============================== -->
  <!-- This document defines default values for *all* web applications      -->
  <!-- loaded into this instance of Tomcat.  As each application is         -->
  <!-- deployed, this file is processed, followed by the                    -->
  <!-- "/WEB-INF/web.xml" deployment descriptor from your own               -->
  <!-- applications.                                                        -->
  <!--                                                                      -->
  <!-- WARNING:  Do not configure application-specific resources here!      -->
  <!-- They should go in the "/WEB-INF/web.xml" file in your application.   -->

  <!-- ================== Built In Servlet Definitions ==================== -->

  <!-- The default servlet for all web applications, that serves static     -->
  <!-- resources.  It processes all requests that are not mapped to other   -->
  <!-- servlets with servlet mappings (defined either here or in your own   -->
  <!-- web.xml file).  This servlet supports the following initialization   -->
  <!-- parameters (default values are in square brackets):                  -->
    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

</web-app>

代码:

$xmlDoc = New-Object System.Xml.XmlDocument
$xmlPath = "C:\path\to\web.xml"
$xmlDoc.Load($xmlPath)

# Create a new instance of XmlWriterSettings and set the properties
$settings.Indent = $true
$settings.IndentChars = "`t"
$settings.NewLineChars = "`r`n"
$settings.NewLineHandling = [System.Xml.NewLineHandling]::Replace
$settings.Encoding = [System.Text.Encoding]::UTF8

# Create a new instance of XmlWriter and save the document
$writer = [System.Xml.XmlWriter]::Create($xmlPath, $settings)
$xmlDoc.Save($writer)
$writer.Flush()
$writer.Close()

结果:

<?xml version="1.0" encoding="utf-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee&#xD;&#xA;                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
    <!-- ======================== Introduction ============================== -->
    <!-- This document defines default values for *all* web applications      -->
    <!-- loaded into this instance of Tomcat.  As each application is         -->
    <!-- deployed, this file is processed, followed by the                    -->
    <!-- "/WEB-INF/web.xml" deployment descriptor from your own               -->
    <!-- applications.                                                        -->
    <!--                                                                      -->
    <!-- WARNING:  Do not configure application-specific resources here!      -->
    <!-- They should go in the "/WEB-INF/web.xml" file in your application.   -->
    <!-- ================== Built In Servlet Definitions ==================== -->
    <!-- The default servlet for all web applications, that serves static     -->
    <!-- resources.  It processes all requests that are not mapped to other   -->
    <!-- servlets with servlet mappings (defined either here or in your own   -->
    <!-- web.xml file).  This servlet supports the following initialization   -->
    <!-- parameters (default values are in square brackets):                  -->
    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
</web-app>

代码:

# Load the XML document
$xmlDoc = New-Object System.Xml.XmlDocument
$xmlPath = "C:\path\to\web.xml"
$xmlDoc.Load($xmlPath)

# Create an XmlWriterSettings object with specified settings
$settings = New-Object System.Xml.XmlWriterSettings
$settings.Indent = $true
$settings.IndentChars = " "
$settings.NewLineChars = [Environment]::NewLine
$settings.NewLineHandling = [System.Xml.NewLineHandling]::Replace
$settings.OmitXmlDeclaration = $true
$settings.Encoding = New-Object System.Text.UTF8Encoding($false)

# Save the XML document with the specified settings
$writer = [System.Xml.XmlWriter]::Create($xmlPath, $settings)
$xmlDoc.Save($writer)
$writer.Close()

结果:

<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee&#xD;&#xA;                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
 <!-- ======================== Introduction ============================== -->
 <!-- This document defines default values for *all* web applications      -->
 <!-- loaded into this instance of Tomcat.  As each application is         -->
 <!-- deployed, this file is processed, followed by the                    -->
 <!-- "/WEB-INF/web.xml" deployment descriptor from your own               -->
 <!-- applications.                                                        -->
 <!--                                                                      -->
 <!-- WARNING:  Do not configure application-specific resources here!      -->
 <!-- They should go in the "/WEB-INF/web.xml" file in your application.   -->
 <!-- ================== Built In Servlet Definitions ==================== -->
 <!-- The default servlet for all web applications, that serves static     -->
 <!-- resources.  It processes all requests that are not mapped to other   -->
 <!-- servlets with servlet mappings (defined either here or in your own   -->
 <!-- web.xml file).  This servlet supports the following initialization   -->
 <!-- parameters (default values are in square brackets):                  -->
 <servlet>
  <servlet-name>default</servlet-name>
  <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
  <init-param>
   <param-name>debug</param-name>
   <param-value>0</param-value>
  </init-param>
  <init-param>
   <param-name>listings</param-name>
   <param-value>false</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
 </servlet>
</web-app>

我被难住了。任何帮助都将不胜感激!

h5qlskok

h5qlskok1#

System.Xml.XmlDocument(PowerShell中为[xml])和System.Xml.Linq.XDocument的- opt-in - insignificant-whitespace-preservation功能:

  • DO适用于 * 元素之间和 * 元素内部的空白 *。
  • 不要应用于元素 * 开始标记 * 内的空格,即不要应用于属性 * 之间的空格。

因此,多行的开始标记,例如:

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  version="4.0">

总是变成一个 * 单行 * 开头标记,带有:

  • 属性用 * 单个空格 * 分隔
  • 属性 values 中的换行符转义为&#xD;&#xA;(如果输入文件具有Windows格式的CRLF换行符)或&#xA;(如果它具有Unix的LF换行符):
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee&#xD;&#xA;                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">

在紧要关头,您可以执行自己的纯文本 * 后处理*,不用说,这是 * 脆弱的 *,可能是 * 特定于文档的 *,只是试图 * 重新创建 * 原始空白-这假定其格式是已知的。
也就是说,对于像您这样的特定文档格式,它可能会起作用(使用[xml] == System.Xml.XmlDocument):

# Note: Be sure to use a *full path*, because .NET's working dir.
#       usually differs from PowerShell's.
$xmlPath = "C:\path\to\web.xml"

# Load the document, with insignificant whitespace preserved.
($webXml = [xml]::new()).PreserveWhitespace = $true
$webXml.Load($xmlPath)

# ... modify it

# ... and save it.
$webXml.Save($xmlPath)

# Post-processing:
# "Re-pretty" the <web-app> element.
# Note: Be sure to match the actual encoding of the file.
$nl = [Environment]::NewLine
(Get-Content -Encoding utf8 $xmlPath) |
  ForEach-Object {
    if ($_ -match '^<web-app ') {
      $_ -replace '(?<=" )', "$nl  " -replace '(&#xD;)?&#xA;', $nl
    } else {
      $_
    }
  } | 
  Set-Content -Encoding uf8 $xmlPath

注:

  • 后期处理假定输入文件使用 platform-native 换行符格式,并且结果文件将使用该格式。
  • 即使这个假设不成立,通常也不会出现问题;确保输入文件的原始换行符格式 * 是 * 可能的,但是需要更多的工作。
  • Windows PowerShell 中(与PowerShell (Core) 7+不同),Set-Content -Encoding utf8总是创建一个UTF-8文件 * 和BOM*。
  • 对于符合标准的XML处理器来说,这应该不是问题,但如果是,请参阅this answer,了解如何在Windows PowerShell中创建无BOM的UTF-8。

相关问题