如何使用vbscript删除XML文件中的特定节点

时间:2008-10-06 09:44:58

标签: xml xpath vbscript

我遇到的问题是我无法选择需要删除的特定XML节点。我已经尝试通过使用XPath来选择节点,XPath适用于某些XML文件,但我无法找到更复杂文件中节点的正确XPath。

是否有人知道可以加载XML文件的免费软件工具,以便用户可以选择特定节点并接收准确的XPath,而无需在路径中进行枚举?

/root/anything[2]< - 不幸的是我不能使用这样的声明,因为元素的数量可能会改变。我需要一个基于属性的表达式。

如果此操作没有免费软件工具,是否有人知道如何选择所需节点?

XML示例:

根节点: SmsFormData

属性: xmlns:xsi =“http://www.w3.org/2001/XMLSchema-instance”xmlns:xsd =“http://www.w3.org/2001/ XMLSchema“FormatVersion =”1.0“xmlns =”http://schemas.microsoft.com/SystemsManagementServer/2005/03/ConsoleFramework“

子节点:表单

属性: Id =“某些GUID”CustomData =“某些数据”FormType =“某种类型”ForceRefresh =“false”

子/节点页面

儿童/儿童/儿童节点页面

属性: VendorId =“VendorName”Id =“some GUID”Assembly =“dll文件名”Namespace =“some Namespace”Type =“some Type”HelpID =“”>

我选择此特定页面的xPath表达式现在为:

xPath = /SmsFormData/Form/Pages/Page[@Id="some Guid"]

要进行选择,我使用以下vbscript代码:

Set objDOM = CreateObject("Msxml2.DOMDocument.4.0") 
objDOM.async = false            
objDOM.load(file)       
set objNode = objDOM.selectSingleNode(xPath)

现在的问题是objNode对象是空的。该节点未被选中,但为什么?

8 个答案:

答案 0 :(得分:2)

这是默认的命名空间问题。加载XML后尝试包含以下代码:

objDom.SetProperty "SelectionNamespaces", "xmlns:cf=""http://schemas.microsoft.com/SystemsManagementServer/2005/03/ConsoleFramework"""

然后在XPath中使用此cf前缀,例如:

objDom.SelectSingleNode("/cf:SmsFormData/cf:Form/cf:Pages/cf:Page[@Id='Some Guid']")

虽然这看起来有点古怪,但这是故意行为。有关详细信息,请查看http://support.microsoft.com/kb/288147,您可能会发现http://msdn.microsoft.com/en-us/library/ms950779.aspx也很有用。

答案 1 :(得分:0)

给出以下XML:

<root>
  <anything foo="bar">value1</anything>
  <anything foo="qux">value2</anything>
</root>

...您可以使用XPath表达式获取第二个节点的值:

/root/anything[@foo="qux"]

(因此,使用@ property =“value”作为选择器而不是编号索引。)

至于一个自动生成这样的查询的工具,适当命名的Visual XPath应该可以解决问题,并且它是免费的(它甚至还带有C#源代码)。

编辑后,通过海报跟进:这种形式的XPath选择对于“简单案例”也适用于最复杂的文档。当然,必须确保你的XPath表达式是正确的,虽然Visual XPath确实会使用数字索引,但它至少会为你提供表达的其余部分,你可以轻松地替换@ property =“value”数字的选择器,并测试结果。

鉴于上面的示例XML,这个VBscript:

objDOM.selectSingleNode("/root/anything[@foo=""qux""]/text()").nodeValue

...返回字符串“value2”:根据您的需要,您可能需要稍微调整一下(再次,像Visual XPath这样的工具,或任何好的XPath reference将帮助您)。

答案 2 :(得分:0)

感谢您的快速回复!这肯定适用于简单的情况,但这在我的具体情况下不起作用:(

因此,让我们进入细节:

根节点: SmsFormData

<强>属性:的xmlns:的xsi = “http://www.w3.org/2001/XMLSchema-instance” 的xmlns:XSD =“http://www.w3.org/2001/ XMLSchema“FormatVersion =”1.0“xmlns =”http://schemas.microsoft.com/SystemsManagementServer/2005/03/ConsoleFramework“

子节点:表单

属性: Id =“某些GUID”CustomData =“某些数据”FormType =“某种类型”ForceRefresh =“false”

子/节点

儿童/儿童/儿童节点页面

<强>属性:厂商ID = “VENDORNAME” ID = “一些GUID” 大会= “DLL文件名” 命名空间= “一些命名空间” 类型= “一些类型” 的helpID = “” &GT;

我选择此特定页面的xPath表达式现在为:

xPath = “/ SmsFormData / Form / Pages / Page [@ Id =”some Guid“]”

要进行选择,我使用以下vbscript代码:

Set objDOM = CreateObject("Msxml2.DOMDocument.4.0") 

objDOM.async = false        
objDOM.load(file)       

set objNode = objDOM.selectSingleNode(xPath) 

现在的问题是objNode对象是空的。该节点未被选中,但为什么?

哦,顺便说一句:感谢Visual XPath提示!我尝试过使用它但不幸的是它采用了枚举方式:/

答案 3 :(得分:0)

您需要使用

将选择语言设置为XPath

objDOM.SetProperty“SelectionLanguage”,“XPath”

设置此属性后,您可以使用完整的XPath访问所需的任何元素

答案 4 :(得分:0)

如果你有Firefox浏览器,你可以简单地安装DOM Inspector(仅适用于Firefox 3.0)和XPather扩展。然后,您可以在DOM Inspector窗口中遍历所需的节点,相应的XPath将显示在同一窗口的XPather工具栏中。

DOM Inspector:https://addons.mozilla.org/en-US/firefox/addon/6622

XPather:https://addons.mozilla.org/en-US/firefox/addon/1192?id=1192

XPather似乎尽可能使用属性(而不是枚举)来识别节点(至少这是我在我的小实验中发现的......)。 希望有所帮助...

答案 5 :(得分:0)

嗯,......我得到的印象是问题必须是基于文件的。 即使我为SelectionLanguage设置了属性,如果我使用枚举的XPath(我使用FireFox XPather获得),节点对象仍然是空的。

有人知道可能出现什么问题吗? xml文件附带Microsoft应用程序,因此应该有效。至少我在打开文件或在应用程序中使用它时没有任何问题,所以语法应该没问题。

或者也许某人有一个vbscript函数遍历整个xml文件以找到所需的节点以便删除它?

答案 6 :(得分:0)

您的问题是您有一个默认命名空间。 XPath默认名称空间始终是“无名称”名称空间。

你需要: -

sNamespaces = "xmlns:cf='http://schemas.microsoft.com/SystemsManagementServer/2005/03/ConsoleFramework'"
objDOM.setProperty "SelectionNamespaces", sNamespaces

现在您可以在XPath中使用: -

xPath = "/cf:SmsFormData/cf:Form/cf:Pages/cf:Page[@Id=""some Guid""]"

答案 7 :(得分:0)

不确定它是否对您有用,但我遇到了类似的问题。

我有一个应用程序生成的XML文件,我需要管理。它的格式是: <LoginData> <GeneralData> <LoginMask>65537</LoginMask> </GeneralData> <UserData> <User> <Username>TEST0</Username> ... </User> <User> <Username>TEST1</Username> ... </User> </UserData> </LoginData>

我需要匹配用户名并删除其他用户标记。

让我(作为一个完整的XML noob)年龄来解决它,但最后我在节点上匹配,并删除父节点的子节点:

对于oXmlDoc.documentElement.selectSingleNode(“UserData”)中的每个x,

.childNodes     if x.getElementsByTagName(“Username”)。item(0).text =“TEST1”then         set exx = x.getElementsByTagName(“Username”)。item(0)         wscript.echo(x.getElementsByTagName( “用户名”)。项(0)的.text)         wScript.echo(x.nodename&amp;“:”&amp; x.text)         x.parentNode.removeChild(x)的     万一 下