我有两个XML文件,一个具有默认名称和值(名为Test.xml
),另一个具有默认名称(名为document.xml
)。目标是用值替换默认名称-但仅在首次出现时使用。
这里是Test.xml
:
<XML-TEST>
<MyText>Dies ist ein Test</MyText>
<MyTexttwo>Dies ist noch ein Test</MyTexttwo>
</XML-TEST>
这里是document.xml
(末尾很多):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas"
xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex"
xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"
xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
xmlns:w10="urn:schemas-microsoft-com:office:word"
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"
xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml"
xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex"
xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"
xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk"
xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml"
xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"
mc:Ignorable="w14 w15 w16se wp14">
<w:body>
<w:p w:rsidR="00E64ECE" w:rsidRDefault="00E64ECE" w:rsidP="00E64ECE">
<w:proofErr w:type="spellStart" />
<w:r>
<w:t>MyText</w:t>
</w:r>
<w:proofErr w:type="spellEnd" />
</w:p>
<w:p w:rsidR="00D50239" w:rsidRPr="00E64ECE" w:rsidRDefault="00E64ECE" w:rsidP="00E64ECE">
<w:r>
<w:t>MyTexttwo</w:t>
</w:r>
<w:bookmarkStart w:id="0" w:name="_GoBack" />
<w:bookmarkEnd w:id="0" />
</w:p>
<w:sectPr w:rsidR="00D50239" w:rsidRPr="00E64ECE">
<w:pgSz w:w="11906" w:h="16838" />
<w:pgMar w:top="1417" w:right="1417" w:bottom="1134" w:left="1417" w:header="708" w:footer="708" w:gutter="0" />
<w:cols w:space="708" />
<w:docGrid w:linePitch="360" />
</w:sectPr>
</w:body>
</w:document>
我在使用PowerShell做些什么?
我将Test.xml
(带有值的那个)保存在哈希表中:
PS> $XMLSourceHashtable Name Value ---- ----- MyText Dies ist ein Test MyTexttwo Dies ist noch ein Test
将document.xml
保存到变量$DocumentXml
中。
使用foreach
替换我需要的内容:
foreach ($key in ($XMLSourceHashtable.GetEnumerator())) {
# If one key.value is "false" replace the 1:1 name with Char
if ($key | Where-Object {$_.Value -eq "false"}) {
#$key.Name.Trim()
#$DocumentXml.InnerXml = $DocumentXml.InnerXml.Replace($key.Name.Trim(), "â˜")
} elseif ($key | Where-Object {$_.Value -eq "true"}) {
# If one key.value is "true" replace the 1:1 name with Char
#$key.Name.Trim()
#$DocumentXml.InnerXml = $DocumentXml.InnerXml.Replace($key.Name.Trim(), "☒")
} else {
# Everything else needs to be replaced by value in hashtable
#Write-Host $key.Name.Trim() "--------------" $key.Value.Trim()
#$DocumentXml.InnerXml = $DocumentXml.InnerXml.Replace($key.Name.Trim(), $key.Value.Trim())
}
}
前两个elseif
工作正常,不应考虑它们。我深信else
。
会发生什么?
当然可以替换文本,但是replace方法将执行以下操作:
document.xml
中的值将按以下方式替换:
“ MyText”→“ Dies ist ein Test”
“ MyTexttwo”→Dies ist ein Testtwo“
但是应该是:
“ MyText”→“ Dies ist ein Test”
“ MyTexttwo”→死于测试“
重点是,“ MyTexttwo”中已识别“ MyText”。每个“名称”都是实际唯一的,但不能像唯一一样处理。我知道可以在首次出现时替换,但只能用RegEx替换。但是我无法将xml转换为regex并再次返回。我还能做些什么吗?
答案 0 :(得分:3)
您的方法太复杂了。使用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="...namespace URI..."
),因此您也需要使用名称空间(请参阅:{{ 3}}):
$document = New-Object xml
$document.Load('Document.xml')
# use a namespace manager to register the w: namespace prefix
$namespaces = New-Object System.Xml.XmlNamespaceManager $document.NameTable
$namespaces.AddNamespace('w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main')
foreach ($item in $XMLSourceHashtable) {
$searchText = $item.Name;
$element = $document.SelectSingleNode("//w:t[.='$searchText']", $namespaces)
$element.InnerText = $item.Value
}
$document.Save('Document_2.xml')
"//w:t[.='$searchText']"
将被插入到//w:t[.='MyText']
之类的XPath表达式中,并且此路径将选择输入XML中所有以<w:t>
作为其值的'MyText'
元素。使用.SelectSingleNode()
仅返回其中的第一个,这似乎是您想要的。
您可以使用.SelectNodes()
和另一个foreach
循环来编辑所有事件:
foreach ($element in $document.SelectNodes("//w:t[.='$searchText']", $namespaces)) {
$element.InnerText = $item.Value
}
答案 1 :(得分:-1)
尽管Tomalak给予从不的建议是很好的建议,但这是您对问题的回答
您使用的Replace方法与WHOLE字符串不匹配。 “ 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()