我为一个名为Space Engineers的alpha /早期访问游戏运行一个专用服务器,偶尔会修补和破坏一些东西,我正在尝试创建一个PowerShell脚本来解决可能发生的问题。我对PowerShell没问题,从不搞乱XML。
第一步是禁用游戏中的所有对象,以便在服务器上减少计算量。像这样 - >
$power = Get-Content 'F:\DedicatedServer\DataDir\SE Survival 2\Saves\VPS RC 1\SANDBOX_0_0_0_.sbs' -raw
$power = $power -replace "<Enabled>true</Enabled>", "<Enabled>false</Enabled>"
$power | Out-File 'F:\DedicatedServer\DataDir\SE Survival 2\Saves\VPS RC 1\SANDBOX_0_0_0_.sbs' -Encoding ascii
第二步和第三步是将所有医疗室和电源(未显示)联机。这就是我遇到麻烦的地方。
[xml]$myXML = Get-Content 'F:\DedicatedServer\DataDir\SE Survival 2\Saves\VPS RC 1\SANDBOX_0_0_0_.sbs'
$ns = New-Object System.Xml.XmlNamespaceManager($myXML.NameTable)
$ns.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
$node = $myXML.SelectNodes('//SectorObjects/MyObjectBuilder_EntityBase/CubeBlocks/MyObjectBuilder_CubeBlock[@xsi:type="MyObjectBuilder_MedicalRoom"]/Enabled', $ns) | % {
#set all med bays to be enabled.
$switch= Select-XML -XML $myXML -XPath $node
$switch.Node.InnerText = $switch.Node.InnerText.Replace("false", "true")
$myXML.Save('F:\DedicatedServer\DataDir\SE Survival 2\Saves\VPS RC 1\SANDBOX_0_0_0_.sbs')
}
以下是删除了非相关数据的XML文件的摘录 -
<?xml version="1.0"?>
<MyObjectBuilder_Sector xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Position>
</Position>
<SectorEvents>
</SectorEvents>
<AppVersion>1044014</AppVersion>
<SectorObjects>
<MyObjectBuilder_EntityBase xsi:type="MyObjectBuilder_CubeGrid">
<EntityId>72230476941025901</EntityId>
<PersistentFlags>CastShadows InScene</PersistentFlags>
<PositionAndOrientation>
</PositionAndOrientation>
<GridSizeEnum>Large</GridSizeEnum>
<CubeBlocks>
<MyObjectBuilder_CubeBlock xsi:type="MyObjectBuilder_CubeBlock">
</MyObjectBuilder_CubeBlock>
<MyObjectBuilder_CubeBlock xsi:type="MyObjectBuilder_MedicalRoom">
<SubtypeName>LargeMedicalRoom</SubtypeName>
<EntityId>72107097601717796</EntityId>
<Min x="4" y="1" z="-1" />
<BlockOrientation Forward="Forward" Up="Up" />
<ColorMaskHSV x="0" y="0.15" z="0.25" />
<Owner>144233151425053409</Owner>
<ShareMode>Faction</ShareMode>
<CustomName>Lurch Enterprises</CustomName>
<ShowOnHUD>false</ShowOnHUD>
<Enabled>false</Enabled>
<SteamUserId>0</SteamUserId>
</MyObjectBuilder_CubeBlock>
XML文件未使用所需更改进行更新。
的每个实例都会改变<MyObjectBuilder_CubeBlock xsi:type="MyObjectBuilder_MedicalRoom">
<Enabled>false</Enabled>
为真。
目前的错误是:
Select-Xml : Cannot validate argument on parameter 'XPath'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At line:16 char:44
+ $switch= Select-XML -XML $myXML -XPath $node
+ ~~~~~
+ CategoryInfo : InvalidData: (:) [Select-Xml], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.SelectXmlCommand
You cannot call a method on a null-valued expression.
At line:17 char:5
+ $switch.Node.InnerText = $switch.Node.InnerText.Replace("false", "true")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
回答了!这是我想要的最终产品。
$filePath = '<your save file path here>\SANDBOX_0_0_0_.sbs'
#troubleshooting script
#switch EVERYTHING off
$power = Get-Content $filePath -raw
$power = $power -replace "<Enabled>true</Enabled>", "<Enabled>false</Enabled>"
$power | Out-File $filePath -Encoding ascii
#turn on medbays, reactors, batteries, solar panels ONLY
[xml]$myXML = Get-Content $filePath
$ns = New-Object System.Xml.XmlNamespaceManager($myXML.NameTable)
$ns.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
$nodes = $myXML.SelectNodes("//SectorObjects/MyObjectBuilder_EntityBase/CubeBlocks/MyObjectBuilder_CubeBlock[@xsi:type='MyObjectBuilder_MedicalRoom']/Enabled|//SectorObjects/MyObjectBuilder_EntityBase/CubeBlocks/MyObjectBuilder_CubeBlock[@xsi:type='MyObjectBuilder_Reactor']/Enabled|//SectorObjects/MyObjectBuilder_EntityBase/CubeBlocks/MyObjectBuilder_CubeBlock[@xsi:type='MyObjectBuilder_BatteryBlock']/Enabled|//SectorObjects/MyObjectBuilder_EntityBase/CubeBlocks/MyObjectBuilder_CubeBlock[@xsi:type='MyObjectBuilder_SolarPanel']/Enabled", $ns)
ForEach($node in $nodes)
{
$node.InnerText = "true"
}
$myXML.Save($filePath)
答案 0 :(得分:0)
为了能够在XPath中使用xsi
前缀,您需要将前缀到命名空间的URI映射注册到XmlNamespaceManager
,然后将XmlNamespaceManager
传递给SelectNodes()
方法:
.....
$ns = New-Object System.Xml.XmlNamespaceManager($myXML.NameTable)
$ns.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
$node = $myXML.SelectNodes("your xpath that contains xsi prefix here", $ns)
.....
更新:
原来在你的XPath中[
之前有隐藏的字符,这就是你得到“无效令牌”错误的原因。我不熟悉PowerShell特定的语法,但这对我来说很好:
[xml]$myXML = Get-Content "F:\DedicatedServer\DataDir\SE Survival 2\Saves\VPS RC 1\SANDBOX_0_0_0_.sbs"
$ns = New-Object System.Xml.XmlNamespaceManager($myXML.NameTable)
$ns.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
$nodes = $myXML.SelectNodes("//SectorObjects/MyObjectBuilder_EntityBase/CubeBlocks/MyObjectBuilder_CubeBlock[@xsi:type='MyObjectBuilder_MedicalRoom']/Enabled", $ns)
ForEach($node in $nodes)
{
$node.InnerText = "true"
}
$myXML.Save("F:\DedicatedServer\DataDir\SE Survival 2\Saves\VPS RC 1\SANDBOX_0_0_0_.sbs")
答案 1 :(得分:0)
如果您计划进行更多XML修改,您可能会发现使用本机XML技术更有用。因此,虽然它没有解决问题,但您尝试使用BaseX为我提供解决方案(完全披露:我是项目团队的成员)。就个人而言,我发现它更简单,而不是使用脚本解决方案。下载后,您可以使用以下命令运行BaseX:
basex -u -i input.xml query.xq
这假设您的输入位于input.xml
文件中。 -u
标志指出应该将文件更新传播回文件。查询存储在query.xq中,并具有以下内容:
//SectorObjects/MyObjectBuilder_EntityBase/CubeBlocks/MyObjectBuilder_CubeBlock[@xsi:type="MyObjectBuilder_MedicalRoom"]/Enabled[. = "false"] ! (replace value of node . with 'true')
这个简单的状态是用文本等于false替换每个Enabled元素以替换为true。它使用简单的XQuery Update表达式。 !
表示法只是一个方便的缩写,以下查询也是如此,但可能稍微更具可读性:
for $e in //SectorObjects/MyObjectBuilder_EntityBase/CubeBlocks/MyObjectBuilder_CubeBlock[@xsi:type="MyObjectBuilder_MedicalRoom"]/Enabled[. = "false"]
return replace value of node . with 'true'
对我来说,这两行(一个用于执行程序,一个用于XQuery)看起来更简单。