【问题标题】:Transform XML using Powershell - what is the equivalent of this Sed command?使用 Powershell 转换 XML - 这个 Sed 命令的等价物是什么?
【发布时间】:2014-05-07 22:25:14
【问题描述】:

我有以下 XML sn-p:

<simpleType name="StatusType">
  <restriction base="integer">
    <enumeration value="1">
      <annotation>
        <documentation>Proposed</documentation>
      </annotation>
    </enumeration>
    <enumeration value="2">
      <annotation>
        <documentation>In Use</documentation>
      </annotation>
    </enumeration>
  </restriction>
</simpleType>

我想变成的样子:

<simpleType name="StatusType">
  <restriction base="integer">
      <enumeration value="1" id="Proposed"/>
      <enumeration value="2" id="In Use"/>
  </restriction>
</simpleType>

我可以在 Linux 上使用 Sed 执行此操作,如下所示:

cat input_file.xml | sed -e '/<enumeration.*[^\/]>/{N;N;N;N;s/\r*\n[ \t]*//g;s/><annotation><documentation>/ id="/;s/<\/documentation><\/annotation><\/enumeration/"\//}'>output_file.xml

我想在 Windows 上实现相同的结果 - 我可以尝试使用 Windows 端口的 Sed,但我更愿意使用 Powershell 之类的东西。 有什么想法可以在 Powershell 中实现吗? Get-Content 有一个看起来很有用的替换功能 - 我可以做一个非常基础的替换,如下所示:

Get-Content input_file.xml | %{ $_ -replace "enumeration", "replacement_text" }

但我不知道下一步该去哪里。

任何指针将不胜感激, 约翰

【问题讨论】:

  • 好吧,既然你似乎可以用正则表达式替换,你可以只做(Get-Content .\data.xml -Raw) -replace '(?s)(&lt;enumeration value="[^"]*")[^&gt;]*&gt;.*?&lt;documentation&gt;([^&lt;]*)&lt;/documentation&gt;.*?&lt;/enumeration&gt;', '$1 id="$2"/&gt;'。如果您想感受一点额外的熟悉感(或者只是想感受一点猫的感觉),您可以使用 cat 别名而不是 Get-Content。
  • 太好了,对我有用,感谢您抽出宝贵时间回答。

标签: powershell


【解决方案1】:

我知道您要求 sed 等效项,但有一个用于操作 XML 的 API,我必须相信这比在 XML 上使用正则表达式更安全。这是执行此操作的一种方法:

$xml = [xml]@'
<simpleType name="StatusType">
  <restriction base="integer">
    <enumeration value="1">
      <annotation>
        <documentation>Proposed</documentation>
      </annotation>
    </enumeration>
    <enumeration value="2">
      <annotation>
        <documentation>In Use</documentation>
      </annotation>
    </enumeration>
  </restriction>
</simpleType>
'@

foreach ($enum in $xml.simpleType.restriction.enumeration) {
    [void]$enum.SetAttribute('id', $enum.annotation.documentation.Trim())
    [void]$enum.RemoveChild($enum.annotation)
    $enum.IsEmpty = $true
}

$xml | Format-Xml

输出:

<simpleType name="StatusType">
  <restriction base="integer">
    <enumeration value="1" id="Proposed" />
    <enumeration value="2" id="In Use" />
  </restriction>
</simpleType>

顺便说一句,Format-Xml 是来自PowerShell Community Extensions 模块的命令。您也可以只使用Save() 方法,例如:

$xml.Save("C:\foo.xml")

【讨论】:

  • 看起来不错,我可能会使用此方法或以下方法以避免使用正则表达式。
【解决方案2】:

我会这样做:

$Text = 
@'
<simpleType name="StatusType">
  <restriction base="integer">
    <enumeration value="1">
      <annotation>
        <documentation>Proposed</documentation>
      </annotation>
    </enumeration>
    <enumeration value="2">
      <annotation>
        <documentation>In Use</documentation>
      </annotation>
    </enumeration>
  </restriction>
</simpleType>
'@

$regex = 
@'
(?ms)<simpleType name="StatusType">
  <restriction base="integer">
    <enumeration value="(\d+)">
      <annotation>
        <documentation>Proposed</documentation>
      </annotation>
    </enumeration>
    <enumeration value="(\d+)">
      <annotation>
        <documentation>In Use</documentation>
      </annotation>
    </enumeration>
  </restriction>
</simpleType>
'@

if ($Text -match $regex)
{
@'
<simpleType name="StatusType">
  <restriction base="integer">
      <enumeration value="{0}" id="Proposed"/>
      <enumeration value="{1}" id="In Use"/>
  </restriction>
</simpleType>
'@ -f $Matches[1,2]
}

<simpleType name="StatusType">
  <restriction base="integer">
      <enumeration value="1" id="Proposed"/>
      <enumeration value="2" id="In Use"/>
  </restriction>
</simpleType>

它并不十分简洁,但对于继承它的人来说,它直观且易于维护。

【讨论】:

  • 不错的解决方案,这里有很多选择供我考虑。
猜你喜欢
  • 2013-05-17
  • 2021-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-25
  • 2011-07-18
  • 2011-03-19
相关资源
最近更新 更多