我正在用PowerShell编写一个修改XML文件的脚本.我以前并没有真正使用过XML,所以我正在摸索这个过程.我了解了如何加载、搜索、插入元素和属性以及保存更改.我遇到的问题是,当我保存更改时,原始XML文件的格式不会保留.尤其是名称空间行,正遭到相当严重的 destruct .对于其他一些上下文,我正在使用位于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>

我try 了很多方法,结果各不相同,但没有一个是令人满意的.我想在元素下面插入一些元素并保存更改,保留上面代码片段中显示的原始格式.这个问题与我正在进行的编辑无关,因为我try 加载XML文件并立即保存.我发现,在保存格式时,根据我try 的内容,格式会以这样或那样的方式被销毁.

我一直在使用.NET System.Xml.XmlDocument类加载和保存该XML文件.我还try 使用XmlWriter和XmlWritterSetting类.

以下是我try 过的方法和结果.

代码:

$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>

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

推荐答案

经过更多的实验,我最终 Select 了mkelement0提供的解决方案,并进行了一些调整:

$xmlPath = "C:\path\to\web.xml"
$newLine = [Environment]::NewLine
$xmlnsPattern = '\s+xmlns\s*=\s*""\s*'

(Get-Content -Path $xmlPath -Encoding utf8NoBOM) | ForEach-Object {
    if ($_ -match '^<web-app ') {
        $_ -replace '\s(?<=" )', "$newLine  " `
           -replace '(&#xD;)?&#xA;', $newLine `
           -replace 'version="4.0">', "version=`"4.0`">$newLine"
    } elseif ($_ -match $xmlnsPattern) {
        $_ -replace $xmlnsPattern, ''
    } else {
        $_
    }
} | Set-Content -Path $xmlPath -Encoding utf8NoBOM -Force

除了一些小的修饰外,我所做的调整删除了后处理后留下的单个空格字符.在插入新的元素 node 后,在开始的<web-app>标记之后插入一个新行,以保持易读性.最后一个更改删除了出现在开始的新元素标记之后的令人讨厌的xmlns="".出现它是因为我使用ImportNode方法从XML片段添加新的元素 node .AFAIK,则无法在导入的片段上包括文档命名空间.(如果有的话,我很想知道!)我本可以在片段中包含名称空间信息,但它很难看,而且代码行更多.

快速说明:PS 5.1中不提供Get-ContentSet-Content编码的utf8NoBOM.

.net相关问答推荐

尽管有`disable`注释,但未 suppress Pylint语法错误

为什么$NULL在ForEach-Object{}和Foreach()中的行为不同?

节省用户在整个应用程序中使用的Flutter

为什么我在环境变量中有不同的值?

.NET 4.5 项目未在 Visual Studio 2022 中编译

是否可以像 WebView 一样在 Windows 窗体中嵌入 Gecko 或 Webkit?

.NET 的 `Array.Sort()` 方法使用的排序算法是稳定的算法吗?

为什么 ?: 会导致转换错误,而 if-else 不会?

Microsoft.Practices.ServiceLocation 来自哪里?

Int 到字节数组

无法在 Windows 10 上安装 Windows SDK 7.1

Double.TryParse 或 Convert.ToDouble - 哪个更快更安全?

当我们按下 Enter 键时启动的 WPF 文本框命令

如何使用 Entity Framework Code First CTP 5 存储图像?

绑定到不在列表中的值的可编辑组合框

为什么 double.NaN 不等于自身?

如何将整个字符串与正则表达式匹配?

如何在安装后立即启动 .NET Windows 服务?

从 Visual Studio 2015 发布 - 允许不受信任的证书

在类型 c# 上切换大小写