From scaekenberghe at common-lisp.net Sat Oct 1 08:48:50 2005 From: scaekenberghe at common-lisp.net (Sven Van Caekenberghe) Date: Sat, 1 Oct 2005 10:48:50 +0200 (CEST) Subject: [cl-soap-cvs] CVS update: cl-soap/src/wsdl.lisp cl-soap/src/xsd.lisp Message-ID: <20051001084850.EC99A880E6@common-lisp.net> Update of /project/cl-soap/cvsroot/cl-soap/src In directory common-lisp.net:/tmp/cvs-serv30878/src Modified Files: wsdl.lisp xsd.lisp Log Message: describe-xsd has been rewritten using the new template system Date: Sat Oct 1 10:48:49 2005 Author: scaekenberghe Index: cl-soap/src/wsdl.lisp diff -u cl-soap/src/wsdl.lisp:1.19 cl-soap/src/wsdl.lisp:1.20 --- cl-soap/src/wsdl.lisp:1.19 Fri Sep 30 19:12:17 2005 +++ cl-soap/src/wsdl.lisp Sat Oct 1 10:48:49 2005 @@ -1,6 +1,6 @@ ;;;; -*- mode: lisp -*- ;;;; -;;;; $Id: wsdl.lisp,v 1.19 2005/09/30 17:12:17 scaekenberghe Exp $ +;;;; $Id: wsdl.lisp,v 1.20 2005/10/01 08:48:49 scaekenberghe Exp $ ;;;; ;;;; The basic WSDL protocol: we parse the generic and soap specific parts ;;;; @@ -376,8 +376,7 @@ (cond ((get-type part) (format stream " of type: ~a~%" (get-type part))) ((get-element part) - (describe-xsd-element xml-schema-definition (get-element part) - :level 5 :stream stream)))) + (describe-xsd-element (get-element part) xml-schema-definition stream 5)))) (defun describe-wsdl-soap (wsdl-document-definitions &key (stream *standard-output*)) "Print a high-level description of the services/ports/operations in wsdl-document-definitions" Index: cl-soap/src/xsd.lisp diff -u cl-soap/src/xsd.lisp:1.21 cl-soap/src/xsd.lisp:1.22 --- cl-soap/src/xsd.lisp:1.21 Fri Sep 30 21:58:05 2005 +++ cl-soap/src/xsd.lisp Sat Oct 1 10:48:49 2005 @@ -1,6 +1,6 @@ ;;;; -*- mode: lisp -*- ;;;; -;;;; $Id: xsd.lisp,v 1.21 2005/09/30 19:58:05 scaekenberghe Exp $ +;;;; $Id: xsd.lisp,v 1.22 2005/10/01 08:48:49 scaekenberghe Exp $ ;;;; ;;;; A partial implementation of the XML Schema Definition standard ;;;; @@ -226,132 +226,6 @@ (defmethod is-plural-p ((xml-schema-element xml-schema-element)) (eql (get-max-occurs xml-schema-element) :unbounded)) -;;; Describing XSD (with pre-rendering of XML) - -(defun indent (n &optional (stream *standard-output*)) - (loop :repeat n :do (write-char #\space stream) (write-char #\space stream))) - -(defmethod describe-multiplicity ((xml-schema-element xml-schema-element)) - (with-slots (min-occurs max-occurs) - xml-schema-element - (cond ((and (zerop min-occurs) (eql max-occurs 1)) "optional") - ((and (eql min-occurs 1) (eql max-occurs 1)) "required") - ((and (eql min-occurs 1) (eql max-occurs :unbounded)) "one or more") - ((and (zerop min-occurs) (eql max-occurs :unbounded)) "zero or more") - (t (format nil "min:~d-max:~d" min-occurs max-occurs))))) - -(defmethod multiplicity-suffix ((xml-schema-element xml-schema-element)) - (with-slots (min-occurs max-occurs) - xml-schema-element - (cond ((and (zerop min-occurs) (eql max-occurs 1)) "?") - ((and (eql min-occurs 1) (eql max-occurs 1)) "") - ((and (eql min-occurs 1) (eql max-occurs :unbounded)) "+") - ((and (zerop min-occurs) (eql max-occurs :unbounded)) "*") - (t (format nil "~d:~d" min-occurs max-occurs))))) - -(defun pre-render-xsd-type (xml-schema-definition type-name &key (level 0) (stream *standard-output*)) - (let* ((type-element (get-element-named xml-schema-definition type-name)) - (type (get-element-type xml-schema-definition type-element))) - (if (typep type 'xsd-complex-type) - (let ((members (get-members type xml-schema-definition))) - (loop :for member :in members :do - (let ((member-name (get-name member)) - (member-type (get-type member))) - (indent level stream) - (if (xsd-primitive-type-name-p member-type) - (format stream " <~a>~a~a>~a~%" - member-name member-type member-name (multiplicity-suffix member)) - (progn - (format stream " <~a>~%" member-name) - (pre-render-xsd-type xml-schema-definition member-type - :level (1+ level) :stream stream) - (indent level stream) - (format stream " ~a>~a~%" member-name (multiplicity-suffix member))))))) - (if (xsd-primitive-type-name-p type) - (progn - (indent level stream) - (format stream " ~a~%" type)) - (error "unexpected type"))))) - -(defun describe-xsd-type (xml-schema-definition type-name &key (level 0) (stream *standard-output*)) - (let* ((type-element (get-element-named xml-schema-definition type-name)) - (type (get-element-type xml-schema-definition type-element))) - (if (typep type 'xsd-complex-type) - (let ((members (get-members type xml-schema-definition))) - (loop :for member :in members :do - (let ((member-name (get-name member)) - (member-type (get-type member))) - (indent level stream) - (if (xsd-primitive-type-name-p member-type) - (format stream " Member ~s of primitive type ~s [~a]~@[ nillable~]~%" - member-name member-type (describe-multiplicity member) (get-nillable member)) - (progn - (format stream " Member ~s [~a]~@[ nillable~]~%" member-name - (describe-multiplicity member) (get-nillable member)) - (describe-xsd-type xml-schema-definition member-type - :level (1+ level) :stream stream)))))) - (if (xsd-primitive-type-name-p type) - (progn - (indent level stream) - (format stream " primitive type ~a~%" type)) - (error "unexpected type"))))) - -(defun describe-xsd-element (xml-schema-definition element &key (level 0) (stream *standard-output*)) - (unless (typep element 'xml-schema-element) - (setf element (get-element-named xml-schema-definition element))) - (let* ((element-type (get-element-type xml-schema-definition element)) - (element-name (get-name element))) - (if (xsd-primitive-type-name-p element-type) - (progn - (indent level stream) - (format stream "Element ~s of primitive type ~s [~a]~@[ nillable~]~%" - element-name element-type (describe-multiplicity element) (get-nillable element)) - (indent level stream) - (format stream " <~a>~a~a>~a~%" - element-name element-type element-name (multiplicity-suffix element))) - (let ((members (get-members element-type xml-schema-definition))) - (indent level stream) - (format stream "Element ~s [~a]~@[ nillable~]~%" element-name - (describe-multiplicity element) (get-nillable element)) - (loop :for member :in members :do - (let ((member-name (get-name member)) - (member-type (get-type member))) - (indent level stream) - (if (xsd-primitive-type-name-p member-type) - (format stream " Member ~s of primitive type ~s [~a]~@[ nillable~]~%" - member-name member-type (describe-multiplicity member) (get-nillable member)) - (progn - (format stream " Member ~s [~a]~@[ nillable~]~%" member-name - (describe-multiplicity member) (get-nillable member)) - (describe-xsd-type xml-schema-definition member-type - :level (1+ level) :stream stream))))) - (indent level stream) - (format stream " <~a>~%" element-name) - (loop :for member :in members :do - (let ((member-name (get-name member)) - (member-type (get-type member))) - (indent level stream) - (if (xsd-primitive-type-name-p member-type) - (format stream " <~a>~a~a>~a~%" - member-name member-type member-name (multiplicity-suffix member)) - (progn - (format stream " <~a>~%" member-name) - (pre-render-xsd-type xml-schema-definition member-type :level (1+ level) :stream stream) - (indent level stream) - (format stream " ~a>~a~%" member-name (multiplicity-suffix member)))))) - (indent level stream) - (format stream " ~a>~a~%" element-name (multiplicity-suffix element)))))) - -(defun describe-xsd (xml-schema-definition &key (stream *standard-output*)) - "Print a high-level description of the top-level elements in xml-schema-definition" - (format stream "XML Schema Definition with target-namespace URI ~s~%" - (get-target-namespace xml-schema-definition)) - (loop :for element :in (get-elements xml-schema-definition) :do - (when (typep element 'xml-schema-element) - (describe-xsd-element xml-schema-definition element - :level 1 :stream stream))) - (values)) - ;;; Template Generation (converting the XSD model to something simpler ;-) ;; an XSD element template looks like this: @@ -496,6 +370,61 @@ (defun resolve-element (element lxml xml-schema-definition namespace) (let ((template (generate-xsd-template element xml-schema-definition))) (resolve-xsd-template template (list lxml) namespace))) + +;;; Describing XSD (print the 'sexpr' format with multiplicity indicators using in input/output binding) + +(defun indent (n &optional (stream *standard-output*)) + (format stream "~&") + (loop :repeat n + :do (write-char #\space stream) (write-char #\space stream))) + +(defun describe-xsd-template-members (members &optional (stream *standard-output*) (level 0)) + (loop :for member :in members :do + (describe-xsd-template member stream (1+ level)))) + +(defun describe-xsd-template (template &optional (stream *standard-output*) (level 0)) + (destructuring-bind (multiplicity element-name &rest contents) + template + (cond ((null contents) + (indent level) + (format stream "(~s)" element-name)) + ((symbolp (first contents)) + (let ((primitive-type (first contents))) + (case multiplicity + ((1 ?) + (indent level) + (format stream "(~s ~s) ~a " element-name primitive-type multiplicity)) + ((+ *) + (indent level) + (format stream "(~s (~s) ~a )" element-name primitive-type multiplicity))))) + (t + (case multiplicity + ((1 ?) + (indent level) + (format stream "(~a" element-name) + (describe-xsd-template-members contents stream level) + (format stream ") ~a " multiplicity)) + ((+ *) + (indent level) + (format stream "(~a (" element-name) + (describe-xsd-template-members contents stream level) + (format stream ") ~a )" multiplicity))))))) + +(defun describe-xsd-element (element xml-schema-definition &optional (stream *standard-output*) (level 0)) + (let ((template (generate-xsd-template element xml-schema-definition))) + (describe-xsd-template template stream level)) + (format stream "~&") + (values)) + +(defun describe-xsd (xml-schema-definition &optional (stream *standard-output*)) + "Print a high-level description of the top-level elements in xml-schema-definition" + (format stream "XML Schema Definition with target-namespace URI ~s~%" + (get-target-namespace xml-schema-definition)) + (loop :for element :in (get-elements xml-schema-definition) :do + (when (typep element 'xml-schema-element) + (describe-xsd-element element xml-schema-definition stream 1))) + (format stream "~&") + (values)) ;;; Primitive Types/Values (types are identified :keywords) From scaekenberghe at common-lisp.net Sat Oct 1 08:48:51 2005 From: scaekenberghe at common-lisp.net (Sven Van Caekenberghe) Date: Sat, 1 Oct 2005 10:48:51 +0200 (CEST) Subject: [cl-soap-cvs] CVS update: cl-soap/test/development.lisp Message-ID: <20051001084851.787AF8853E@common-lisp.net> Update of /project/cl-soap/cvsroot/cl-soap/test In directory common-lisp.net:/tmp/cvs-serv30878/test Modified Files: development.lisp Log Message: describe-xsd has been rewritten using the new template system Date: Sat Oct 1 10:48:50 2005 Author: scaekenberghe Index: cl-soap/test/development.lisp diff -u cl-soap/test/development.lisp:1.1 cl-soap/test/development.lisp:1.2 --- cl-soap/test/development.lisp:1.1 Fri Sep 30 21:59:26 2005 +++ cl-soap/test/development.lisp Sat Oct 1 10:48:50 2005 @@ -1,6 +1,6 @@ ;;;; -*- Mode: LISP -*- ;;;; -;;;; $Id: development.lisp,v 1.1 2005/09/30 19:59:26 scaekenberghe Exp $ +;;;; $Id: development.lisp,v 1.2 2005/10/01 08:48:50 scaekenberghe Exp $ ;;;; ;;;; Development scratch pad ;;;; @@ -324,5 +324,128 @@ (values nil nil) (error "Expected a <~a> element" tag-name))))) (t (error "Cannot resolve element ~s of type ~s" element element-type))))) + +;;; Describing XSD (with pre-rendering of XML) + +(defmethod describe-multiplicity ((xml-schema-element xml-schema-element)) + (with-slots (min-occurs max-occurs) + xml-schema-element + (cond ((and (zerop min-occurs) (eql max-occurs 1)) "optional") + ((and (eql min-occurs 1) (eql max-occurs 1)) "required") + ((and (eql min-occurs 1) (eql max-occurs :unbounded)) "one or more") + ((and (zerop min-occurs) (eql max-occurs :unbounded)) "zero or more") + (t (format nil "min:~d-max:~d" min-occurs max-occurs))))) + +(defmethod multiplicity-suffix ((xml-schema-element xml-schema-element)) + (with-slots (min-occurs max-occurs) + xml-schema-element + (cond ((and (zerop min-occurs) (eql max-occurs 1)) "?") + ((and (eql min-occurs 1) (eql max-occurs 1)) "") + ((and (eql min-occurs 1) (eql max-occurs :unbounded)) "+") + ((and (zerop min-occurs) (eql max-occurs :unbounded)) "*") + (t (format nil "~d:~d" min-occurs max-occurs))))) + +(defun pre-render-xsd-type (xml-schema-definition type-name &key (level 0) (stream *standard-output*)) + (let* ((type-element (get-element-named xml-schema-definition type-name)) + (type (get-element-type xml-schema-definition type-element))) + (if (typep type 'xsd-complex-type) + (let ((members (get-members type xml-schema-definition))) + (loop :for member :in members :do + (let ((member-name (get-name member)) + (member-type (get-type member))) + (indent level stream) + (if (xsd-primitive-type-name-p member-type) + (format stream " <~a>~a~a>~a~%" + member-name member-type member-name (multiplicity-suffix member)) + (progn + (format stream " <~a>~%" member-name) + (pre-render-xsd-type xml-schema-definition member-type + :level (1+ level) :stream stream) + (indent level stream) + (format stream " ~a>~a~%" member-name (multiplicity-suffix member))))))) + (if (xsd-primitive-type-name-p type) + (progn + (indent level stream) + (format stream " ~a~%" type)) + (error "unexpected type"))))) + +(defun describe-xsd-type (xml-schema-definition type-name &key (level 0) (stream *standard-output*)) + (let* ((type-element (get-element-named xml-schema-definition type-name)) + (type (get-element-type xml-schema-definition type-element))) + (if (typep type 'xsd-complex-type) + (let ((members (get-members type xml-schema-definition))) + (loop :for member :in members :do + (let ((member-name (get-name member)) + (member-type (get-type member))) + (indent level stream) + (if (xsd-primitive-type-name-p member-type) + (format stream " Member ~s of primitive type ~s [~a]~@[ nillable~]~%" + member-name member-type (describe-multiplicity member) (get-nillable member)) + (progn + (format stream " Member ~s [~a]~@[ nillable~]~%" member-name + (describe-multiplicity member) (get-nillable member)) + (describe-xsd-type xml-schema-definition member-type + :level (1+ level) :stream stream)))))) + (if (xsd-primitive-type-name-p type) + (progn + (indent level stream) + (format stream " primitive type ~a~%" type)) + (error "unexpected type"))))) + +(defun describe-xsd-element (xml-schema-definition element &key (level 0) (stream *standard-output*)) + (unless (typep element 'xml-schema-element) + (setf element (get-element-named xml-schema-definition element))) + (let* ((element-type (get-element-type xml-schema-definition element)) + (element-name (get-name element))) + (if (xsd-primitive-type-name-p element-type) + (progn + (indent level stream) + (format stream "Element ~s of primitive type ~s [~a]~@[ nillable~]~%" + element-name element-type (describe-multiplicity element) (get-nillable element)) + (indent level stream) + (format stream " <~a>~a~a>~a~%" + element-name element-type element-name (multiplicity-suffix element))) + (let ((members (get-members element-type xml-schema-definition))) + (indent level stream) + (format stream "Element ~s [~a]~@[ nillable~]~%" element-name + (describe-multiplicity element) (get-nillable element)) + (loop :for member :in members :do + (let ((member-name (get-name member)) + (member-type (get-type member))) + (indent level stream) + (if (xsd-primitive-type-name-p member-type) + (format stream " Member ~s of primitive type ~s [~a]~@[ nillable~]~%" + member-name member-type (describe-multiplicity member) (get-nillable member)) + (progn + (format stream " Member ~s [~a]~@[ nillable~]~%" member-name + (describe-multiplicity member) (get-nillable member)) + (describe-xsd-type xml-schema-definition member-type + :level (1+ level) :stream stream))))) + (indent level stream) + (format stream " <~a>~%" element-name) + (loop :for member :in members :do + (let ((member-name (get-name member)) + (member-type (get-type member))) + (indent level stream) + (if (xsd-primitive-type-name-p member-type) + (format stream " <~a>~a~a>~a~%" + member-name member-type member-name (multiplicity-suffix member)) + (progn + (format stream " <~a>~%" member-name) + (pre-render-xsd-type xml-schema-definition member-type :level (1+ level) :stream stream) + (indent level stream) + (format stream " ~a>~a~%" member-name (multiplicity-suffix member)))))) + (indent level stream) + (format stream " ~a>~a~%" element-name (multiplicity-suffix element)))))) + +(defun describe-xsd (xml-schema-definition &key (stream *standard-output*)) + "Print a high-level description of the top-level elements in xml-schema-definition" + (format stream "XML Schema Definition with target-namespace URI ~s~%" + (get-target-namespace xml-schema-definition)) + (loop :for element :in (get-elements xml-schema-definition) :do + (when (typep element 'xml-schema-element) + (describe-xsd-element xml-schema-definition element + :level 1 :stream stream))) + (values)) ;;;; eof From scaekenberghe at common-lisp.net Sat Oct 1 09:24:13 2005 From: scaekenberghe at common-lisp.net (Sven Van Caekenberghe) Date: Sat, 1 Oct 2005 11:24:13 +0200 (CEST) Subject: [cl-soap-cvs] CVS update: public_html/google-adwords-api.html public_html/index.html Message-ID: <20051001092413.CB187880E6@common-lisp.net> Update of /project/cl-soap/cvsroot/public_html In directory common-lisp.net:/tmp/cvs-serv646 Modified Files: google-adwords-api.html index.html Log Message: documentation update to latest state of code Date: Sat Oct 1 11:24:11 2005 Author: scaekenberghe Index: public_html/google-adwords-api.html diff -u public_html/google-adwords-api.html:1.2 public_html/google-adwords-api.html:1.3 --- public_html/google-adwords-api.html:1.2 Tue Sep 27 22:35:16 2005 +++ public_html/google-adwords-api.html Sat Oct 1 11:24:11 2005 @@ -35,110 +35,63 @@ Binding: api:InfoServiceSoapBinding SOAP style [document] Operation: getUnitCountForMethod Input: getUnitCountForMethodRequest - Element "getUnitCountForMethod" [required] - Member "service" of primitive type "string" [required] - Member "method" of primitive type "string" [required] - Member "startDate" of primitive type "date" [required] - Member "endDate" of primitive type "date" [required] - <getUnitCountForMethod> - <service>string</service> - <method>string</method> - <startDate>date</startDate> - <endDate>date</endDate> - </getUnitCountForMethod> + (getUnitCountForMethod + ("service" :STRING) 1 + ("method" :STRING) 1 + ("startDate" :DATE) 1 + ("endDate" :DATE) 1 ) 1 Output: getUnitCountForMethodResponse - Element "getUnitCountForMethodResponse" [required] - Member "getUnitCountForMethodReturn" of primitive type "long" [required] - <getUnitCountForMethodResponse> - <getUnitCountForMethodReturn>long</getUnitCountForMethodReturn> - </getUnitCountForMethodResponse> + (getUnitCountForMethodResponse + ("getUnitCountForMethodReturn" :LONG) 1 ) 1 Operation: getUnitCount Input: getUnitCountRequest - Element "getUnitCount" [required] - Member "startDate" of primitive type "date" [required] - Member "endDate" of primitive type "date" [required] - <getUnitCount> - <startDate>date</startDate> - <endDate>date</endDate> - </getUnitCount> + (getUnitCount + ("startDate" :DATE) 1 + ("endDate" :DATE) 1 ) 1 Output: getUnitCountResponse - Element "getUnitCountResponse" [required] - Member "getUnitCountReturn" of primitive type "long" [required] - <getUnitCountResponse> - <getUnitCountReturn>long</getUnitCountReturn> - </getUnitCountResponse> + (getUnitCountResponse + ("getUnitCountReturn" :LONG) 1 ) 1 Operation: getMethodCost Input: getMethodCostRequest - Element "getMethodCost" [required] - Member "service" of primitive type "string" [required] - Member "method" of primitive type "string" [required] - Member "date" of primitive type "date" [required] - <getMethodCost> - <service>string</service> - <method>string</method> - <date>date</date> - </getMethodCost> + (getMethodCost + ("service" :STRING) 1 + ("method" :STRING) 1 + ("date" :DATE) 1 ) 1 Output: getMethodCostResponse - Element "getMethodCostResponse" [required] - Member "getMethodCostReturn" of primitive type "int" [required] - <getMethodCostResponse> - <getMethodCostReturn>int</getMethodCostReturn> - </getMethodCostResponse> + (getMethodCostResponse + ("getMethodCostReturn" :INT) 1 ) 1 Operation: getUsageQuotaThisMonth Input: getUsageQuotaThisMonthRequest - Element "getUsageQuotaThisMonth" [required] - <getUsageQuotaThisMonth> - </getUsageQuotaThisMonth> + ("getUsageQuotaThisMonth") Output: getUsageQuotaThisMonthResponse - Element "getUsageQuotaThisMonthResponse" [required] - Member "getUsageQuotaThisMonthReturn" of primitive type "long" [required] - <getUsageQuotaThisMonthResponse> - <getUsageQuotaThisMonthReturn>long</getUsageQuotaThisMonthReturn> - </getUsageQuotaThisMonthResponse> + (getUsageQuotaThisMonthResponse + ("getUsageQuotaThisMonthReturn" :LONG) 1 ) 1 Operation: getOperationsQuotaThisMonth Input: getOperationsQuotaThisMonthRequest - Element "getOperationsQuotaThisMonth" [required] - <getOperationsQuotaThisMonth> - </getOperationsQuotaThisMonth> + ("getOperationsQuotaThisMonth") Output: getOperationsQuotaThisMonthResponse - Element "getOperationsQuotaThisMonthResponse" [required] - Member "getOperationsQuotaThisMonthReturn" of primitive type "long" [required] - <getOperationsQuotaThisMonthResponse> - <getOperationsQuotaThisMonthReturn>long</getOperationsQuotaThisMonthReturn> - </getOperationsQuotaThisMonthResponse> + (getOperationsQuotaThisMonthResponse + ("getOperationsQuotaThisMonthReturn" :LONG) 1 ) 1 Operation: getOperationCount Input: getOperationCountRequest - Element "getOperationCount" [required] - Member "startDate" of primitive type "date" [required] - Member "endDate" of primitive type "date" [required] - <getOperationCount> - <startDate>date</startDate> - <endDate>date</endDate> - </getOperationCount> + (getOperationCount + ("startDate" :DATE) 1 + ("endDate" :DATE) 1 ) 1 Output: getOperationCountResponse - Element "getOperationCountResponse" [required] - Member "getOperationCountReturn" of primitive type "long" [required] - <getOperationCountResponse> - <getOperationCountReturn>long</getOperationCountReturn> - </getOperationCountResponse> + (getOperationCountResponse + ("getOperationCountReturn" :LONG) 1 ) 1 The input and output characteristics of each operation are described in some detail. - Example template XML code of actaul input and output are also given. + Example lisp template code of actaul input and output are also given (along with multiplicity indication, whether elements are required, optional, can occur zero ore more times, or one or more times).
Given that you understand a particular operation, you can implement it quite easily. -
(defun get-method-cost (service method &optional (date (get-universal-time))) +For the Google AdWords API, some headers are required. - The method implemented above requires some parameters, specified to the framework as a simple alist. + The method implemented above requires some parameters, specified to the framework as a structured alist. With debugging enabled (using (setf *debug-stream* *output-stream*)), executing the call looks as follows:(defun get-method-cost (service method &optional (date (ut))) (wsdl-soap-call (wsdl-cache-get "https://adwords.google.com:443/api/adwords/v2/InfoService?wsdl") "getMethodCost" - :input `("service" ,service - "method" ,method - "date" ,date) - :headers `("email" ,*google-adwords-email* - "password" ,*google-adwords-password* - "useragent" ,*google-adwords-user-agent* - "token" ,*google-adwords-token* - "clientEmail" ,*google-client-email*)))+ :input `("getMethodCost" ("service" ,service "method" ,method "date" ,date)) + :headers (make-google-headers)))
CL-SOAP 85 > (get-method-cost "InfoService" "getMethodCost") @@ -190,8 +143,7 @@ </units> </soapenv:Header> <soapenv:Body> - <getMethodCostResponse - xmlns="https://adwords.google.com/api/adwords/v2"> + <getMethodCostResponse xmlns="https://adwords.google.com/api/adwords/v2"> <getMethodCostReturn>1</getMethodCostReturn> </getMethodCostResponse> </soapenv:Body> @@ -203,8 +155,185 @@ Some sensitive data fields have been marked with X's. XML was beautified a little bit ;-) Note that two values are returned: the actual value and the headers. - Stay tuned for more complicated examples later on. -$Id: google-adwords-api.html,v 1.2 2005/09/27 20:35:16 scaekenberghe Exp $
++ A more complicated example comes from the introduction to the Google AdWords API: estimating the traffic for keywords. Again, we first look at the interpreted WSDL: +
CL-SOAP 43 > (describe-wsdl-soap (wsdl-cache-get "https://adwords.google.com:443/api/adwords/v2/TrafficEstimatorService?wsdl")) +WSDL Document Definitions + Service: TrafficEstimatorService + Port: TrafficEstimatorService + SOAP Address Location "https://adwords.google.com:443/api/adwords/v2/TrafficEstimatorService" + Binding: api:TrafficEstimatorServiceSoapBinding SOAP style [document] + Operation: estimateKeywordList + Input: estimateKeywordListRequest + (estimateKeywordList + (keywordRequests ( + ("id" :LONG) ? + ("type" :STRING) ? + ("text" :STRING) ? + ("maxCpc" :LONG) ? + ("negative" :BOOLEAN) ? ) + )) 1 + Output: estimateKeywordListResponse + (estimateKeywordListResponse + (estimateKeywordListReturn ( + ("id" :LONG) ? + ("impressions" :INT) 1 + ("ctr" :FLOAT) 1 + ("cpc" :LONG) 1 + ("avgPosition" :FLOAT) 1 + ("notShownPerDay" :INT) 1 ) + )) 1 + Operation: estimateAdGroupList + Input: estimateAdGroupListRequest + (estimateAdGroupList + (adGroupRequests ( + ("id" :INT) ? + ("maxCpc" :LONG) ? + (keywordRequests ( + ("id" :LONG) ? + ("type" :STRING) ? + ("text" :STRING) ? + ("maxCpc" :LONG) ? + ("negative" :BOOLEAN) ? ) + )) + )) 1 + Output: estimateAdGroupListResponse + (estimateAdGroupListResponse + (estimateAdGroupListReturn ( + ("id" :INT) ? + (keywordEstimates ( + ("id" :LONG) ? + ("impressions" :INT) 1 + ("ctr" :FLOAT) 1 + ("cpc" :LONG) 1 + ("avgPosition" :FLOAT) 1 + ("notShownPerDay" :INT) 1 ) + )) + )) 1 + Operation: estimateCampaignList + Input: estimateCampaignListRequest + (estimateCampaignList + (campaignRequests ( + ("id" :INT) ? + ("optInSearchNetwork" :BOOLEAN) ? + ("optInContentNetwork" :BOOLEAN) ? + (geoTargeting + ("countries" (:STRING) * ) + ("regions" (:STRING) * ) + ("metros" (:STRING) * ) + ("cities" (:STRING) * )) ? + (languageTargeting + ("languages" (:STRING) * )) ? + (adGroupRequests ( + ("id" :INT) ? + ("maxCpc" :LONG) ? + (keywordRequests ( + ("id" :LONG) ? + ("type" :STRING) ? + ("text" :STRING) ? + ("maxCpc" :LONG) ? + ("negative" :BOOLEAN) ? ) + )) + )) + )) 1 + Output: estimateCampaignListResponse + (estimateCampaignListResponse + (estimateCampaignListReturn ( + ("id" :INT) ? + (adGroupEstimates ( + ("id" :INT) ? + (keywordEstimates ( + ("id" :LONG) ? + ("impressions" :INT) 1 + ("ctr" :FLOAT) 1 + ("cpc" :LONG) 1 + ("avgPosition" :FLOAT) 1 + ("notShownPerDay" :INT) 1 ) + )) + )) + )) 1+ Next we define our little lisp function: +(defun estimate-keyword-list (keywords) + "((text type max-cpc)*) where type is Broad|Phrase|Exact" + (wsdl-soap-call (wsdl-cache-get "https://adwords.google.com:443/api/adwords/v2/TrafficEstimatorService?wsdl") + "estimateKeywordList" + :input `("estimateKeywordList" + ("keywordRequests" + ,(mapcar #'(lambda (keyword) + (destructuring-bind (text type max-cpc) + keyword + `("text" ,text "type" ,type "maxCpc" ,max-cpc))) + keywords))) + :headers (make-google-headers)))+ Now we can test it, passing multiple requests and receiving multiple responses: +CL-SOAP 192 > (estimate-keyword-list '(("flowers" "Broad" 50000) ("tree" "Broad" 50000))) +;; SOAP CALL sending: +<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:google="https://adwords.google.com/api/adwords/v2" xmlns="https://adwords.google.com/api/adwords/v2"> + <soapenv:Header> + <token>XXX</token> + <useragent>cl-soap-testing</useragent> + <password>XXX</password> + <clientEmail>sven at beta9.be</clientEmail> + <email>svc at mac.com</email> + </soapenv:Header> + <soapenv:Body> + <estimateKeywordList> + <keywordRequests> + <type>Broad</type> + <text>flowers</text> + <maxCpc>50000</maxCpc> + </keywordRequests> + <keywordRequests> + <type>Broad</type> + <text>tree</text> + <maxCpc>50000</maxCpc> + </keywordRequests> + </estimateKeywordList> + </soapenv:Body> +</soapenv:Envelope> +;; SOAP CALL receiving: +<soapenv:Envelope + xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:xsd="http://www.w3.org/1999/XMLSchema" + xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"> + <soapenv:Header> + <responseTime + soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next" + soapenv:mustUnderstand="0" + xmlns="https://adwords.google.com/api/adwords/v2"> + 412 + </responseTime> + <operations + soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next" + soapenv:mustUnderstand="0" + xmlns="https://adwords.google.com/api/adwords/v2"> + 2 + </operations> + <units + soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next" + soapenv:mustUnderstand="0" + xmlns="https://adwords.google.com/api/adwords/v2"> + 50 + </units> + </soapenv:Header> + <soapenv:Body> + <estimateKeywordListResponse xmlns="https://adwords.google.com/api/adwords/v2"> + <estimateKeywordListReturn> + <avgPosition>4.537519</avgPosition> + <cpc>50000</cpc> + <ctr>0.01547993</ctr> + <id>-1</id> + <impressions>7263</impressions> + <notShownPerDay>288532</notShownPerDay> + </estimateKeywordListReturn> + <estimateKeywordListReturn> + <avgPosition>2.8274193</avgPosition> + <cpc>50000</cpc> + <ctr>0.012525387</ctr> + <id>-1</id> + <impressions>18177</impressions> + <notShownPerDay>397941</notShownPerDay> + </estimateKeywordListReturn> + </estimateKeywordListResponse> + </soapenv:Body> +</soapenv:Envelope> + +("estimateKeywordListResponse" + ("estimateKeywordListReturn" + (("id" -1 "impressions" 7263 "ctr" 0.01547993 "cpc" 50000 "avgPosition" 4.537519 "notShownPerDay" 288532) + ("id" -1 "impressions" 18177 "ctr" 0.012525387 "cpc" 50000 "avgPosition" 2.8274193 "notShownPerDay" 397941)))) + +((GOOGLE:|responseTime| . "412") (GOOGLE:|operations| . "2") (GOOGLE:|units| . "50"))+ That is all for now! More example and testing code can be found in the project's source tree. +$Id: google-adwords-api.html,v 1.3 2005/10/01 09:24:11 scaekenberghe Exp $