如何使用MSDeploy Parameters.xml文件更改名称空间中的XML元素?

时间:2011-04-29 09:22:08

标签: xml xpath msdeploy

我无法使用MSDeploy更改 Web.config 中的元素。我的 Parameters.xml 文件:

         

  

<parameterEntry
  kind="XmlFile"
  scope="\\web.config$"
  match="//spring/objects/object[@id='CultureResolver']/@type" />

Web.config 的相关部分:

<spring>
    <objects xmlns="http://www.springframework.net">

        <object id="CultureResolver" type="Spring.Globalization.Resolvers.SessionCultureResolver, Spring.Web">
             <!--configure for server--> 
            <property name="DefaultCulture" value="en" />
        </object>
    </objects>
</spring>

2 个答案:

答案 0 :(得分:8)

XPath技巧

你的例子有点棘手(起初)。但是这个XPath查询虽然要长得多,但应该可以工作:

//spring/*[local-name() = 'objects' and namespace-uri() = 'http://www.springframework.net']/*[@id='CultureResolver' and local-name() = 'object' and namespace-uri() = 'http://www.springframework.net']/@type

我在this answer中向SO问题c# - Declare namespaces within XPath expression发现了这个技巧,但是在我已经发布了这个答案(最初)之后我才发现它。

我已经将下面的大部分原始答案留下了,我还添加了有关我的原始答案是如何错误的额外部分。

我的例子

我想为NLog执行此操作;这是我的 NLog.config 文件的一个示例:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" throwExceptions="true">

  ...

  <targets>
    <target name="HipChat" xsi:type="MethodCall" className="DbNecromancer.Logging, DbNecromancer" methodName="SendHipChatRoomNotification">
      <parameter layout="1234567" name="roomId" />
      <parameter layout="blah-blah-blah" name="authToken" />
      <parameter layout="${message-layout}" name="message" />
      <parameter layout="${level}" name="nLogLevel" />
    </target>
  </targets>

  ...
</nlog>

这是来自 Parameters.xml 文件的相关XPath查询,用于更改layout元素的parameter属性,值为&#34; roomId&#34;对于name属性:

/nlog/targets/target[@name='HipChat']/parameter[@name='roomId']/@layout

您可以使用this free online XPath tester确认上述XPath无法与所需属性匹配。您还可以使用Web Deploy本身确认它失败!

但是,无论是在线测试器还是通过Web Deploy,我都可以在不使用通配符或删除 NLog.config 中的命名空间声明的情况下使用它。诀窍是添加名称空间前缀。

以下是 NLog.config 中的修改行:

<nlog:nlog xmlns:nlog="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" throwExceptions="true">
    ...
</nlog:nlog>

这是修改过的XPath查询:

/nlog:nlog/targets/target[@name='HipChat']/parameter[@name='roomId']/@layout

您的示例

我无法通过在示例使用命名空间的情况下添加前缀(并且我没有使用Spring的项目)来让您的示例在在线测试人员中工作。当我尝试添加前缀时测试仪的输出:

  

错误 - 无法评估XPath表达式:前缀必须解析为命名空间:spring

但是,通过执行以下操作,我能够让它工作(我认为可能是&#39;正确&#39;)。

这是我改变的XML中的行:

<spring xmlns="" xmlns:spring="http://www.springframework.net">
    <spring:objects>
        ...
    </spring:objects>

这是修改过的XPath查询:

/spring/spring:objects/object[@id='CultureResolver']/@type

为什么&#39;我的例子&#39;和你的榜样&#39;是(Subtly)错误

我似乎(几乎没有)理解的问题是,声明没有前缀的命名空间与声明带前缀的命名空间非常不同。

声明带有前缀的命名空间只是声明命名空间及其前缀,但它不会更改任何元素的命名空间

声明没有前缀的命名空间使该命名空间成为其定义的元素和该元素的所有子元素的默认命名空间。

因此,对于您的示例,您可以修改XML中的以下行,并且原始XPath查询将起作用:

    <objects xmlns:spring="http://www.springframework.net">

[只需将spring前缀添加到命名空间。]

因为(或者根据我的工作假设)将前缀添加到命名空间声明中而不向objects元素(及其所有子节点)添加前缀是&#39;显著&#39;修改XML因为从名称空间中删除了这些元素

要在不修改XML语义的情况下正确添加前缀,您的XML应如下所示:

<spring>
    <spring:objects xmlns:spring="http://www.springframework.net">
        <spring:object id="CultureResolver" type="Spring.Globalization.Resolvers.SessionCultureResolver, Spring.Web">
             <!--configure for server--> 
            <spring:property name="DefaultCulture" value="en" />
        </spring:object>
    </spring:objects>
</spring>

你的XPath查询应该是这样的:

//spring/spring:objects/spring:object[@id='CultureResolver']/@type

唯一的问题是不起作用(在the online tester中,也可能不在MSDeploy中)。

上述方法不起作用,因为XPath引擎需要注册名称空间(与XML文档本身声明的名称空间分开)。但是,正如Web Deploy和在线测试人员所做的那样,XML文档的根元素中的任何声明都会自动注册。这非常有用,因为我不知道在使用Web Deploy参数转换时注册命名空间的任何方法。

有关更深入的说明,请参阅我的相关问题Do XML namespaces need to be declared in the root element to be matchable by an XPath query?的答案。

您的(更正)示例

XML:

<spring xmlns:spring="http://www.springframework.net">
    <spring:objects>
        <spring:object id="CultureResolver" type="Spring.Globalization.Resolvers.SessionCultureResolver, Spring.Web">
             <!--configure for server--> 
            <spring:property name="DefaultCulture" value="en" />
        </spring:object>
    </spring:objects>
</spring>

XPath查询:

//spring/spring:objects/spring:object[@id='CultureResolver']/@type

结论

如果您不介意长XPath查询,请使用顶部的技巧。否则,修改XML名称空间声明,使它们包含前缀,并且它们位于XML文档的根元素中。

答案 1 :(得分:7)

问题是<objects/>元素上的名称空间声明。您的XPath查询没有匹配项,因为没有<objects/>元素具有空命名空间(这是查询所查找的内容)。

现在,在XPath中指定XML命名空间是一个棘手的问题(在这种情况下甚至是不可能的),所以我建议你改用这个表达式:

"//spring/*/*[@id='CultureResolver']/@type"

... HTH