InnerXml替换,但仅替换一次

InnerXml替换,但仅替换一次,xml,powershell,replace,Xml,Powershell,Replace,我有两个XML文件,一个具有默认名称和值(名为Test.XML),另一个仅具有默认名称(名为document.XML)。目标是用值替换默认名称-但仅在第一次出现时 下面是Test.xml: 艾因试验 这是诺克海因试验 下面是document.xml(差不多在末尾): 我的文本 Mytext2 我在用PowerShell做什么? 我将Test.xml(带值的)保存在哈希表中: PS> $XMLSourceHashtable Name Value

我有两个XML文件,一个具有默认名称和值(名为
Test.XML
),另一个仅具有默认名称(名为
document.XML
)。目标是用值替换默认名称-但仅在第一次出现时

下面是
Test.xml


艾因试验
这是诺克海因试验
下面是
document.xml
(差不多在末尾):


我的文本
Mytext2
我在用PowerShell做什么?

  • 我将
    Test.xml
    (带值的)保存在哈希表中:

    PS> $XMLSourceHashtable Name Value ---- ----- MyText Dies ist ein Test MyTexttwo Dies ist noch ein Test
  • 前两个
    elseif
    工作正常,不应予以考虑。这是我所关心的
    其他

    发生了什么事?

    文本当然要替换,但替换方法将执行以下操作:

    正在替换
    document.xml
    中的值,如下所示:

    “我的文本”→ “测试”中的“测试”
    “MyTexttwo”→ 死亡是“测试二”

    但它应该是:

    “我的文本”→ "模具是ein测试“
    “MyTexttwo”→ 这是一个“无条件的测试”


    关键是,“MyText”在“MyTexttwo”中被识别。每个“名称”“实际上是独一无二的,但处理起来却不像独一无二。我知道第一次出现时可以替换,但只能使用正则表达式。但是我不能将xml转换成正则表达式,然后再转换回来。还有什么我可以做的吗?

    尽管Tomalak给了永不使用XML中的字符串替换的建议是一个很好的建议,这里是对您问题的一个回答,重点是,“MyText”在“MyTexttwo”中被识别。每个“名称”实际上都是唯一的,但其处理方式并不是唯一的

    您使用的替换方法与整个字符串不匹配。“MyTextTwo”以“MyText”开头,因此在您的函数中,部分名称被替换。“MyTextTwo”就不再存在了

    以便仅在完整字符串匹配而不是部分匹配时进行替换。如果您仍然想使用字符串替换,我建议:

    $nameToReplace = $key.Name.Trim()
    $DocumentXml.InnerXml = $DocumentXml.InnerXml -replace "\A$nameToReplace\z", $key.Value.Trim()
    
    \A
    \z
    符号是锚定符,用于告诉正则表达式替换字符串必须与您给定的字符串完全一致。(位置性资产)

    如果您还需要确保仅在外壳也匹配的情况下进行更换,您可以使用

    $nameToReplace = $key.Name.Trim()
    $DocumentXml.InnerXml = $DocumentXml.InnerXml -creplace "\A$nameToReplace\z", $key.Value.Trim()
    

    你的方法太复杂了。使用XPath。原则上-加载、修改、保存:

    $document = New-Object xml
    $document.Load('Document.xml')
    
    $element = $document.SelectSingleNode("//some/path")
    $element.InnerText = "some new value"
    
    $document.Save('Document_2.xml')
    
    这里唯一稍微复杂的是,您正在处理Word文档,它们使用XML名称空间(在XML源代码中写为
    xmlns:foo=“…名称空间URI…”
    ),因此您也需要使用名称空间(请参阅:):

    “//w:t[.='$searchText']”
    将被插入到XPath表达式中,如
    //w:t[.='MyText']
    ——此路径将选择输入XML中具有
    'MyText'
    作为其值的所有
    元素。使用
    .SelectSingleNode()
    将只返回其中的第一个,这似乎是您想要的

    您可以使用
    .SelectNodes()
    和另一个
    foreach
    循环编辑所有发生的事件:

    foreach ($element in $document.SelectNodes("//w:t[.='$searchText']", $namespaces)) {
        $element.InnerText = $item.Value
    }
    

    请接受这个普遍的建议。绝不,绝不,绝不在XML源代码上使用字符串替换工具。这永远是一件完全错误的事情。很难解释这有多错,因为对初学者来说这看起来很容易。简单地说,决不做那件事。学习正确的工具(在本例中为XPath)并使用它们。@Tomalak回答,编辑了我的答案。“也许你可以把你的警告放在你的答案中,作为一个区块引语,这样它会更突出吗?”托马拉克说!不要在XML上使用正则表达式或字符串替换。这是一件可怕的事情。Hello Theo,这不起作用-不幸的是,在我以任何方式将$key.Name设置为引号“”之前,变量将不再解析。因此,不会对document.xml进行任何更改。我正在尝试此操作-请旁观我添加的有关名称空间使用的内容,您可能也需要此内容。@Ansgar Ahh,既然xml已在问题中格式化,它就更清晰了。是的,我认为你是对的。我想你解决这个问题的方法是目前为止最好的。。但是我的PS在$namespaces.AddNamespace上向我抛出了一个错误-“没有methode AddNamespace”我只有“Add()”作为选项。@J.Doe如果你是对的,我使用了链接答案中的代码,没有测试它。我已经更正了我的答案。
    foreach ($element in $document.SelectNodes("//w:t[.='$searchText']", $namespaces)) {
        $element.InnerText = $item.Value
    }