Как я могу получить узлы XML из этого XML в классическом ASP (MSXML)? - PullRequest
1 голос
/ 07 декабря 2009

ОК, я в своем уме. Похоже, это должно быть совершенно тривиально, но через час я все еще не могу заставить его работать.

Я пытаюсь получить список часовых поясов из 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 - я подозреваю, что это как-то связано с пространствами имен (я знаю, у меня были проблемы с этим в прошлом), но я не уверен, что.

Кто-нибудь может указать, что я делаю не так? Любая помощь высоко ценится!

Ответы [ 2 ]

2 голосов
/ 07 декабря 2009

Ваше заблуждение заключается в обработке пространства имен по умолчанию. Здесь нет такого понятия, как пространство имен по умолчанию для выражений 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".

1 голос
/ 07 декабря 2009

Вы не можете переопределить пространство имен по умолчанию, используемое 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, вы можете указать DOMDocument для внутреннего использования ServerXMLHttp при включении свойства ServerHTTPRequest. (Кстати, ваш код, похоже, выполняет избыточную потоковую передачу DOMDocument, предоставляемого свойством ResponseXML, в новый DOMDocument).
  • Я предпочитаю использовать версию MSXML 3.0, поскольку она гарантированно присутствует на поддерживаемых платформах. Если нет, то я бы установил 6.0 и использовал это.
  • Указание SelectionLanguage для XPath на 4.0 или выше является избыточным, это язык выбора по умолчанию.
...