1

好吧,我已经束手无策了。这似乎应该是一件完全微不足道的事情,但一个小时后我仍然无法让它工作。

我正在尝试从Campaign Monitor API获取时区列表;不幸的是,我需要在其中执行此操作的页面是用经典的 ASP/Javascript 编写的,所以我不能只使用 API 包装器。

我提出这样的要求:

var request = Server.CreateObject("Msxml2.ServerXMLHTTP");

request.open("GET", apiurl + "/User.GetTimezones?ApiKey=" + apikey, false);
request.send();

正确的 XML 将从服务器返回,如下所示:

<anyType d1p1:type="ArrayOfString" xmlns:d1p1="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://api.createsend.com/api/"> 
    <string>(GMT) Casablanca</string> 
    <string>(GMT) Coordinated Universal Time</string> 
    <string>(GMT) Greenwich Mean Time : Dublin, Edinburgh, Lisbon, London</string> 
    <string>(GMT) Monrovia, Reykjavik</string> 
    <string>(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna</string> 
    <string>(GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague</string> 
    <string>(GMT+01:00) Brussels, Copenhagen, Madrid, Paris</string> 
    (...and so on - I've truncated for the purpose of this question)
</anyType>

然后我将此 XML 加载到 MSXML 文档中:

var response = Server.CreateObject("Msxml2.DOMDocument.4.0");
response.async = false;
response.validateOnParse = false;
response.resolveExternals = false;

response.setProperty("SelectionNamespaces", "xmlns:d1p1='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://api.createsend.com/api/'");
response.setProperty("SelectionLanguage", "XPath");

if (response.load(request.responseXML)) 
{
    // If I uncomment this, the XML is correctly written out
    // Response.Write(response.xml);

    var nodes = response.selectNodes("//string");

    // No nodes are found, this is always zero
    Response.Write(nodes.length);

    for (var x = 0; x < nodes.length; x++) 
    {
        // Do something with each time zone value here
    }
}

正如您从评论中看到的那样,问题是无论我做什么,我似乎都无法匹配那些“字符串”节点。当谈到 ASP/Javascript 时,我很生疏——我怀疑这与命名空间有关(我知道我过去遇到过问题),但我不确定是什么。

谁能指出我做错了什么?非常感谢任何帮助!

4

2 回答 2

2

您的误解在于默认命名空间处理。这里没有 XPath 表达式的默认命名空间之类的东西 - 您必须使用前缀,即使它在 XML 中没有前缀:

var nsDef = "";
nsDef = nsDef + "xmlns:d1p1='http://www.w3.org/2001/XMLSchema-instance' ";
nsDef = nsDef + "xmlns:api='http://api.createsend.com/api/' ";

response.setProperty("SelectionNamespaces", nsDef);
response.setProperty("SelectionLanguage", "XPath");

var nodes = response.selectNodes("//api:string");

如果不使用前缀,则 XPath 表达式将在空名称空间中处理。这就是您无法使用 选择任何内容的原因"//string"

于 2009-12-07T17:26:40.110 回答
1

您不能覆盖 XPath 使用的默认名称空间。在 MSXML 中,XPath 默认命名空间始终是“无名称”命名空间。但是,属性中使用的别名集不需要SelectionNamespaces与文档中的别名匹配(当然,在可能的情况下使用相同的别名是有意义的)。

像这样定义您的一组命名空间:-

var ns = "xmlns:a='http://api.createsend.com/api/' "
       + "xmlns:d1p1='http://www.w3.org/2001/XMLSchema-instance'"
response.setProperty("SelectionNamespaces", ns);

现在您可以选择所有string元素: -

var nodes = response.selectNodes("//a:string");

这就是我将其作为一个整体进行编码的方式:-

var response = Server.CreateObject("MSXML2.DOMDocument.3.0");  // or use 6.0 but not 4.0
response.async = false;
response.validateOnParse = false;
response.resolveExternals = false;


response.setProperty("ServerHTTPRequest", true); 

if (response.load(apiurl + "/User.GetTimezones?ApiKey=" + apikey)) 
{

    var ns = "xmlns:a='http://api.createsend.com/api/' "
           + "xmlns:d1p1='http://www.w3.org/2001/XMLSchema-instance'"
    response.setProperty("SelectionNamespaces", ns);

    response.setProperty("SelectionLanguage", "XPath");  // remove for 4.0 or above is default

    var nodes = response.selectNodes("//a:string");

    Response.Write(nodes.length);

    for (var x = 0; x < nodes.length; x++) 
    {
        // Do something with each time zone value here
    }
}

笔记:-

  • 对于 GET 请求,不需要使用单独的 ServerXMLHttp 对象,您可以通过启用该ServerHTTPRequest属性来指示 DOMDocument 在内部使用 ServerXMLHttp。(顺便说一句,您的代码似乎将 ResponseXML 属性公开的 DOMDocument 流式传输到新的 DOMDocument 中)。
  • 我更喜欢使用 3.0 版本的 MSXML,因为它保证在支持的平台上存在。如果没有,那么我将安装 6.0 并使用它。
  • 在 4.0 或更高版本上将 SelectionLanguage 指定为 XPath 是多余的,它是默认选择语言。
于 2009-12-07T18:15:01.880 回答