Curtis Mack Curtis.Mack@lgan.com Looking Glass Analytics www.lgan.com

Similar documents
Using SAS BI Web Services and PROC SOAP in a Service-Oriented Architecture Dan Jahn, SAS, Cary, NC

Dynamic Decision-Making Web Services Using SAS Stored Processes and SAS Business Rules Manager

Leveraging the SAS Open Metadata Architecture Ray Helm & Yolanda Howard, University of Kansas, Lawrence, KS

Integration of Hotel Property Management Systems (HPMS) with Global Internet Reservation Systems

Introduction to Web services for RPG developers

Managing Qualtrics Survey Distributions and Response Data with SAS

CONTRACT MODEL IPONZ DESIGN SERVICE VERSION 2. Author: Foster Moore Date: 20 September 2011 Document Version: 1.7

Secure XML API Integration Guide. (with FraudGuard add in)

Mobility Information Series

Home Network Administration Protocol (HNAP) Whitepaper

XML Processing and Web Services. Chapter 17

REST web services. Representational State Transfer Author: Nemanja Kojic

Domain Name System (DNS)

What is Distributed Annotation System?

Creating Web Services in NetBeans

You can do THAT with SAS Software? Using the socket access method to unite SAS with the Internet

The presentation explains how to create and access the web services using the user interface. WebServices.ppt. Page 1 of 14

Leveraging APIs in SAS to Create Interactive Visualizations

VoIP LAB. 陳 懷 恩 博 士 助 理 教 授 兼 所 長 國 立 宜 蘭 大 學 資 訊 工 程 研 究 所 TEL: # 255

What is SOAP MTOM? How it works?

ACCREDITATION COUNCIL FOR PHARMACY EDUCATION. CPE Monitor. Technical Specifications

HTTP - METHODS. Same as GET, but transfers the status line and header section only.

Lecture Notes course Software Development of Web Services

Real-Time Connectivity Specifications For. 270/271 and 276/277 Inquiry Transactions. United Concordia Dental (UCD)

Extracting YouTube videos using SAS. Dr Craig Hansen

Designing RESTful Web Applications

SOAP WSDL & HTTP MIME REST Web Services Companion Guide HIPAA Operating Rules (HOpR) CORE Phase II

Testing Work Group. Document Status: Project: WS-I Monitor Tool Functional Specification [MonitorSpecification.doc]

DEVELOPING CONTRACT - DRIVEN WEB SERVICES USING JDEVELOPER. The purpose of this tutorial is to develop a java web service using a top-down approach.

HOST EUROPE CLOUD STORAGE REST API DEVELOPER REFERENCE

Getting Started Guide for Developing tibbr Apps

NYSP Web Service FAQ

Usage of Evaluate Client Certificate with SSL support in Mediator and CentraSite

StreamServe Persuasion SP4 Service Broker

Chart of Accounts (COA) Validation Service. 6/11/2012 University at California, Berkeley IS&T, Application Services

17 March 2013 NIEM Web Services API Version 1.0 URI:

Web Services Technologies

Reading Delimited Text Files into SAS 9 TS-673

2- Electronic Mail (SMTP), File Transfer (FTP), & Remote Logging (TELNET)

Easy CramBible Lab DEMO ONLY VERSION Test284,IBM WbS.DataPower SOA Appliances, Firmware V3.6.0

PlayReady App Creation Tutorial

Freight Tracking Web Service Implementation Guide

Using Web Services to exchange information via XML

Technical Paper. Reading Delimited Text Files into SAS 9

Identifying Invalid Social Security Numbers

Understanding Slow Start

2- Electronic Mail (SMTP), File Transfer (FTP), & Remote Logging (TELNET)

RingMaster Software Version 7.6 Web Services API User Guide

DOCUMENTS ON WEB OBJECTIVE QUESTIONS

CDW DATA QUALITY INITIATIVE

Technical Interface Description

Using ilove SharePoint Web Services Workflow Action

Load Testing SOAs which Utilize Web Services

Internet Technologies. World Wide Web (WWW) Proxy Server Network Address Translator (NAT)

Common definitions and specifications for OMA REST interfaces

Using web service technologies for incremental, real-time data transfers from EDC to SAS

Web Services Security SOAP Messages with Attachments (SwA) Profile 1.1

WEB SERVICES. Revised 9/29/2015

VMware vcenter Log Insight Developer's Guide

Better Safe than Sorry: A SAS Macro to Selectively Back Up Files

TCP Packet Tracing Part 1

Intel Rack Scale Architecture Storage Services

Title page. Alcatel-Lucent 5620 SERVICE AWARE MANAGER 13.0 R7

[MS-SPEMAWS]: SharePoint Web Service Protocol. Intellectual Property Rights Notice for Open Specifications Documentation

WIRIS quizzes web services Getting started with PHP and Java

CTIS 256 Web Technologies II. Week # 1 Serkan GENÇ

SW : : Introduction to Web Services with IBM Rational Application Developer V6

Copyright 2012, Oracle and/or its affiliates. All rights reserved.

Encryption in SAS 9.2

Developing a Web Service Based Application for Mobile Client

How to consume a Domino Web Services from Visual Studio under Security

Creating Form Rendering ASP.NET Applications

Visualize Your Cloud Data Using the Graph Template Language

Types of Cloud Computing

Secure XML API Integration Guide - Periodic and Triggered add in

9-26 MISSOVER, TRUNCOVER,

Fundamentals of Web Programming a

SUGI 29 Coders' Corner

JASPERREPORTS SERVER WEB SERVICES GUIDE

9.4 BI Web. SAS Services. Developer's Guide. SAS Documentation

Consuming and Producing Web Services with Web Tools. Christopher M. Judd. President/Consultant Judd Solutions, LLC

The BritNed Explicit Auction Management System. Kingdom Web Services Interfaces

VIRTUAL LABORATORY: MULTI-STYLE CODE EDITOR

Juniper Secure Analytics

GSM. Quectel Cellular Engine. HTTP Service AT Commands GSM_HTTP_ATC_V1.2

A Signing Proxy for Web Services Security. Dr. Ingo Melzer RIC/ED

Building and Using Web Services With JDeveloper 11g

HTTP and HTTPS Statistics Services

Working With Virtual Hosts on Pramati Server

Effective Use of SQL in SAS Programming

Accessing Data with ADOBE FLEX 4.6

An Introduction to SAS/SHARE, By Example

DNS Update API November 15, 2006 Version 2.0.3

Transcription:

Curtis Mack Curtis.Mack@lgan.com Looking Glass Analytics www.lgan.com

Weather Charting Graphing Geocoding Mapping Large Selection of other sites Your SAS Applications Infinite Possibilities on your own Servers

SOAP Object based More structured Well integrated into code development tools. More powerful Harder to code REST Parameter Based Less Structured More Human Readable Easier to code Has become more popular

Simple Object Access Protocol (Quick Overview) WSDL File Object Defined on the Web Server Serialization WSDL WSDL File Services File HTTP Client Application

Representational State Transfer (Quick Overview) Parameter driven application on the web server URL with parameters, sometimes in JSON format Return Data, often in XML, JSON, or image formats. HTTP Client Application

Get the WSDL file from the service http://www.service.com/service.ext?w SDL Select the desired action Find the definition for the object the action request expects Find the definition for the object the service returns.

<?xml version="1.0" encoding="utf-8"?> -<wsdl:definitionsxmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" -xmlns:tm="http://microsoft.com/wsdl/mime/textmatching/" -xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" -xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" -xmlns:tns="http://www.wslite.strikeiron.com" -xmlns:s=http://www.w3.org/2001/xmlschema -xmlns:soap12=http://schemas.xmlsoap.org/wsdl/soap12/ -xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" -targetnamespace="http://www.wslite.strikeiron.com" -xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> These SOAP examples are using services <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">retrieves U.S. demographic information from the U.S. Census Bureau's Census 2000. Provides demographic, from social, the economic, company and housingstrike characteristics Iron. for the given ZIPCode. </wsdl:documentation> - <wsdl:types> Their free CensusLite service is used in - <s:schema elementformdefault="qualified" targetnamespace="http://www.wslite.strikeiron.com"> - <s:element name="getcensusinfoforzipcode"> this demonstration. - <s:complextype> - <s:sequence> <s:element www.strikeiron.com minoccurs="0" maxoccurs="1" name="zipcode" type="s:string" /> </s:sequence> </s:complextype> </s:element> - <s:element name="getcensusinfoforzipcoderesponse"> - <s:complextype> - <s:sequence> <s:element minoccurs="0" maxoccurs="1" name="getcensusinfoforzipcoderesult" t type="tns:censusoutput" /> </s:sequence> </s:complextype> </s:element>

Free open source tool for reading WSDL files and generating sample SOAP calls http://www.soapui.org/

Could write code to parse the results SAS XML Mapper, is a much better Approach GUI interface that reads an existing XML file The user selects the desired data elements Creates a.map file mapping XML structures into a rectangular format that can be stored in a SAS dataset

XML Mapper occationaly fails when reading complicated XML structures Edit the XML file in a text editor Remove unneeded branches Maintain the Hierarchy of the needed information Open the edited file in XML Mapper to create the XML Map. May need to edit more than once to get difference data elements out of the same XML file

Must create code to communicate with server via TCP/IP port 80. SOAP_CALL Macro A relatively simple macro that can handle many SOAP calls Parameters: Host = The URL of the server domain. ServiceLocation = URL of the service SoapAction = The name of the Action, including the namespace. SchemaReference = Any actions or object definitions used in the SOAP body must be prefixed with a namespace alias. This parameter contains the definition of that alias. ContentXML = Name of file containing the XML being sent to the action. OutputXML = Name of the file to which the results will be written.

options mprint; %let WorkDir = G:\PNWSUG\Papers\Soap\CensusLite; %SOAP_Call(wslite.strikeiron.com, http://wslite.strikeiron.com/censusinfolite01/censusinfolite.asmx, http://www.wslite.strikeiron.com/getcensusinfoforzipcode, %nrstr(wsl="http://www.wslite.strikeiron.com"), &WorkDir\ZIP98501SOAPBody.xml, &WorkDir\results.xml); filename CensMap "&WorkDir\CensusInformation.map"; libname Census xml "&WorkDir\results.xml" xmlmap=censmap access=readonly; Data ZIP98501Census; set Census.Censusinformation; run;

filename SoapSrv socket "wslite.strikeiron.com:80" lrecl=32767 termstr=crlf; filename SoapRtrn "G:\PNWSUG\Papers\Soap\CensusLite\results.xml" RECFM=N; filename ContXML "G:\PNWSUG\Papers\Soap\CensusLite\ZIP98501SOAPBody.xml"; data _ContXML(drop = TotalXMLLength); retain TotalXMLLength 0; length content $32767; infile ContXML end=xmleof; input; content = strip(_infile_); TotalXMLLength = TotalXMLLength + length(content) + 1; if xmleof then call symput('totalxmllength',totalxmllength); run; data _null_; length content1 content2 $32767; retain mode 1 TotalReturn ReturnLength 0; infile SoapSrv truncover; file SoapSrv; if _n_ = 1 then do; content1 = '<soapenv:envelope ' 'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"' " " 'xmlns:' "wsl=""http://www.wslite.strikeiron.com""" ">" '<soapenv:body>'; content2 = "</soapenv:body>" "</soapenv:envelope>"; ContentLength = length(content1) + length(content2) + 101 + 4 + int( 101 / 32767); call symput ('ContentLength',ContentLength); put "POST http://wslite.strikeiron.com/censusinfolite01/censusinfolite.asmx HTTP/1.1" / 'Content-Type: text/xml; charset=utf-8' / "SOAPAction: ""http://www.wslite.strikeiron.com/getcensusinfoforzipcode""" / "Host: wslite.strikeiron.com" / 'Content-Length: ' ContentLength /; put content1 @; currentlinelength = length(content1); fc = open("_contxml"); do until(fetch(fc)); thisline = strip(getvarc(fc,1)); if sum(length(thisline),currentlinelength) + 1 >= 32767 then do; put; currentlinelength = 0; put thisline@@; currentlinelength = sum(length(thisline),currentlinelength) + 1; rc = close(fc); put; put content2 ; put 'OPTIONS / HTTP/1.1' / "Host: http://wslite.strikeiron.com/censusinfolite01/censusinfolite.asmx" / 'Connection: Close' /; if mode = 1 then do; input thisrec $ 1-32767; if thisrec =: "Content-Length:" then do; ReturnLength = input(scan(thisrec,2,':'),10.); call symput('returnlength',returnlength); if thisrec = " " then mode = 2; if mode = 2 then do; nextreturn = ReturnLength - TotalReturn; input thisrec $varying32767. nextreturn; file SoapRtrn; put thisrec; TotalReturn = TotalReturn + length(thisrec); if TotalReturn >= ReturnLength then mode = 3; if mode = 3 then do; input; run; Code generated by a call to the SOAP_CALL macro. Some code review.

filename SoapSrv socket "wslite.strikeiron.com:80" lrecl=32767 termstr=crlf; filename SoapRtrn "G:\PNWSUG\Papers\Soap\CensusLite\results.xml" RECFM=N; filename ContXML "G:\PNWSUG\Papers\Soap\CensusLite\ZIP98501SOAPBody.xml"; data _ContXML(drop = TotalXMLLength); retain TotalXMLLength 0; length content $32767; infile ContXML end=xmleof; input; content = strip(_infile_); TotalXMLLength = TotalXMLLength + length(content) + 1; if xmleof then call symput('totalxmllength',totalxmllength); run; Length of the Envelope Start + Length of the Envelope End + Size of the Body Text + End-of-Lines <wsl:getcensusinfoforzipcode> between them + text. <wsl:zipcode>98501</wsl:zipcode> data _null_; length content1 content2 $32767; retain mode 1 TotalReturn ReturnLength 0; End-of-Lines infile SoapSrv truncover; between logical file SoapSrv; records. if _n_ = 1 then </wsl:getcensusinfoforzipcode> do; content1 = '<soapenv:envelope ' 'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"' " " 'xmlns:' "wsl=""http://www.wslite.strikeiron.com""" ">" '<soapenv:body>'; content2 = "</soapenv:body>" "</soapenv:envelope>"; ContentLength = length(content1) + length(content2) + 101 + 4 + int( 101 / 32767); call symput ('ContentLength',ContentLength); put "POST http://wslite.strikeiron.com/censusinfolite01/censusinfolite.asmx HTTP/1.1" / 'Content-Type: text/xml; charset=utf-8' / "SOAPAction: ""http://www.wslite.strikeiron.com/getcensusinfoforzipcode""" / "Host: wslite.strikeiron.com" / 'Content-Length: ' ContentLength /; put @; currentlinelength content1 retain TotalXMLLength = length(content1); = '<soapenv:envelope 0; ' fc = open("_contxml"); do until(fetch(fc)); length content $32767; thisline = strip(getvarc(fc,1)); if infile sum(length(thisline),currentlinelength) ContXML end=xmleof; + 1 >= 32767 then do; put; currentlinelength = 0; input; '<soapenv:body>'; put thisline@@; currentlinelength sum(length(thisline),currentlinelength) + 1; content2 = = "</soapenv:body>" strip(_infile_); rc = close(fc); put; "</soapenv:envelope>"; put content2 ; put 'OPTIONS / HTTP/1.1' / "Host: http://wslite.strikeiron.com/censusinfolite01/censusinfolite.asmx" / 'Connection: Close' /; if _n_ data = 1 then _ContXML(drop do; = TotalXMLLength); if mode = 1 then do; input thisrec $ 1-32767; if thisrec =: "Content-Length:" then do; ReturnLength = input(scan(thisrec,2,':'),10.); call symput('returnlength',returnlength); if thisrec = " " then mode = 2; References. if mode = 2 then do; nextreturn = ReturnLength - TotalReturn; input thisrec $varying32767. nextreturn; file SoapRtrn; put thisrec; TotalReturn = TotalReturn + length(thisrec); if TotalReturn >= ReturnLength then mode = 3; if mode = 3 then do; input; run; Start of Define port the writing file and Block. Port Define Open variables the port containing as both the envelope the Read outgoing the start file containing and end incoming the object file being reference. sent Calculate and count the total the Bytes. bytes. 'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"' " " 'xmlns:' "wsl=""http://www.wslite.strikeiron.com""" data _null_; ">" length content1 content2 $32767; filename SoapSrv socket "wslite.strikeiron.com:80" lrecl=32767 termstr=crlf; retain mode 1 TotalReturn ReturnLength 0; filename SoapRtrn "G:\PNWSUG\Papers\Soap\CensusLite\results.xml" RECFM=N; filename TotalXMLLength ContXML "G:\PNWSUG\Papers\Soap\CensusLite\ZIP98501SOAPBody.xml"; = TotalXMLLength infile SoapSrv + length(content) truncover; + 1; ContentLength if xmleof then = call length(content1) symput('totalxmllength',totalxmllength); file SoapSrv; + length(content2) + 101 + 4 + run; int( 101 / 32767);

filename fc SoapSrv = open("_contxml"); socket "wslite.strikeiron.com:80" lrecl=32767 termstr=crlf; put "POST filename SoapRtrn "G:\PNWSUG\Papers\Soap\CensusLite\results.xml" RECFM=N; filename do ContXML until(fetch(fc)); http://wslite.strikeiron.com/censusinfolite01/censusinfolite.asmx "G:\PNWSUG\Papers\Soap\CensusLite\ZIP98501SOAPBody.xml"; put; HTTP/1.1 data 'Content-Type: _ContXML(drop = TotalXMLLength); retain TotalXMLLength thisline 0; = strip(getvarc(fc,1)); text/xml; put content2 charset=utf-8' ; / length "SOAPAction: content $32767; infile ContXML if end=xmleof; sum(length(thisline),currentlinelength) ""http://www.wslite.strikeiron.com/getcensusinfoforzipcode""" put 'OPTIONS / HTTP/1.1' / "Host: + 1 >= 32767 then do; / input; content "Host: = strip(_infile_); wslite.strikeiron.com" / TotalXMLLength put; = TotalXMLLength http://wslite.strikeiron.com/censusinfolite01/censusinfolite.asmx" + length(content) + 1; if xmleof then call symput('totalxmllength',totalxmllength); 'Content-Length: ' ContentLength /; run; currentlinelength / 'Connection: = Close' 0; /; put content1 @; currentlinelength = length(content1); data _null_; length content1 content2 $32767; retain mode 1 TotalReturn ReturnLength 0; infile SoapSrv put truncover; thisline@@; file SoapSrv; if _n_ = 1 then do; content1 = '<soapenv:envelope ' 'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"' " " 'xmlns:' "wsl=""http://www.wslite.strikeiron.com""" ">" '<soapenv:body>'; content2 = "</soapenv:body>" "</soapenv:envelope>"; ContentLength rc = close(fc); = length(content1) + length(content2) + 101 + 4 + int( 101 / 32767); call symput ('ContentLength',ContentLength); put "POST http://wslite.strikeiron.com/censusinfolite01/censusinfolite.asmx HTTP/1.1" / 'Content-Type: text/xml; charset=utf-8' / "SOAPAction: ""http://www.wslite.strikeiron.com/getcensusinfoforzipcode""" / "Host: wslite.strikeiron.com" / 'Content-Length: ' ContentLength /; put content1 @; currentlinelength = length(content1); fc = open("_contxml"); do until(fetch(fc)); thisline = strip(getvarc(fc,1)); if sum(length(thisline),currentlinelength) + 1 >= 32767 then do; put; currentlinelength = 0; put thisline@@; currentlinelength = sum(length(thisline),currentlinelength) + 1; rc = close(fc); put; put content2 ; put 'OPTIONS / HTTP/1.1' / "Host: http://wslite.strikeiron.com/censusinfolite01/censusinfolite.asmx" / 'Connection: Close' /; if mode = 1 then do; input thisrec $ 1-32767; if thisrec =: "Content-Length:" then do; ReturnLength = input(scan(thisrec,2,':'),10.); call symput('returnlength',returnlength); if thisrec = " " then mode = 2; if mode = 2 then do; nextreturn = ReturnLength - TotalReturn; input thisrec $varying32767. nextreturn; file SoapRtrn; put thisrec; TotalReturn = TotalReturn + length(thisrec); if TotalReturn >= ReturnLength then mode = 3; if mode = 3 then do; input; run; currentlinelength = sum(length(thisline),currentlinelength) + 1; Close the Soap Envelope Read in the package body contents and write Write Post an the extra Start the Soap them to the port. Envelope OPTIONS to service the port. request to force an extra end of line character.

filename SoapSrv socket "wslite.strikeiron.com:80" lrecl=32767 termstr=crlf; filename SoapRtrn "G:\PNWSUG\Papers\Soap\CensusLite\results.xml" RECFM=N; filename ContXML "G:\PNWSUG\Papers\Soap\CensusLite\ZIP98501SOAPBody.xml"; data _ContXML(drop = TotalXMLLength); retain TotalXMLLength 0; Block length content $32767; infile Ignore Block to ContXML end=xmleof; the to Read read results the the from length Returned input; content of = strip(_infile_); the return envelope TotalXMLLength = TotalXMLLength + length(content) + 1; the OPTIONS Envelope request. and if xmleof then call symput('totalxmllength',totalxmllength); run; write from it out the to returned the SOAP destination header. file. data _null_; length content1 content2 $32767; retain mode 1 TotalReturn ReturnLength 0; infile SoapSrv truncover; file SoapSrv; if _n_ = 1 then do; content1 = '<soapenv:envelope ' 'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"' " " 'xmlns:' "wsl=""http://www.wslite.strikeiron.com""" ">" '<soapenv:body>'; content2 = "</soapenv:body>" "</soapenv:envelope>"; ContentLength = length(content1) + length(content2) + 101 + 4 + int( 101 / 32767); call symput ('ContentLength',ContentLength); put "POST http://wslite.strikeiron.com/censusinfolite01/censusinfolite.asmx HTTP/1.1" / 'Content-Type: text/xml; charset=utf-8' / "SOAPAction: ""http://www.wslite.strikeiron.com/getcensusinfoforzipcode""" / if mode "Host: wslite.strikeiron.com" = 1 then / do; 'Content-Length: ' ContentLength /; if mode = 2 then do; put content1 @; currentlinelength input thisrec = length(content1); $ 1-32767; fc = open("_contxml"); do until(fetch(fc)); thisline = strip(getvarc(fc,1)); if sum(length(thisline),currentlinelength) + 1 >= 32767 then do; put; file currentlinelength SoapRtrn; = 0; put thisline@@; put thisrec; currentlinelength = sum(length(thisline),currentlinelength) + 1; rc = close(fc); put; if thisrec = " " then mode = 2; put content2 ; put 'OPTIONS / HTTP/1.1' / "Host: http://wslite.strikeiron.com/censusinfolite01/censusinfolite.asmx" / 'Connection: Close' /; if mode = 1 then do; input thisrec $ 1-32767; if thisrec =: "Content-Length:" then do; ReturnLength = input(scan(thisrec,2,':'),10.); call symput('returnlength',returnlength); if thisrec = " " then mode = 2; if mode = 2 then do; nextreturn = ReturnLength - TotalReturn; input thisrec $varying32767. nextreturn; file SoapRtrn; put thisrec; TotalReturn = TotalReturn + length(thisrec); if TotalReturn >= ReturnLength then mode = 3; if mode = 3 then do; input; run; nextreturn = ReturnLength - TotalReturn; if thisrec =: "Content-Length:" then do; if mode = 3 then do; input thisrec $varying32767. nextreturn; ReturnLength = input(scan(thisrec,2,':'),10.); input; call symput('returnlength',returnlength); run; TotalReturn = TotalReturn + length(thisrec); if TotalReturn >= ReturnLength then mode = 3;

filename XMLMap "c:\censuslite.map"; libname results XML "c:\results.xml" xmlmap= XMLMap access=readonly;

PROC SOAP Only Available in 9.2 phase 1 and later Handles Authentication Handles Proxy Servers proc soap in=request out=response url=" http://www.soapserver.com/soapservice.ext " soapaction="http://www.soapnamespace.com/methodname"; run;

FILENAME request "temprq.xml" ; FILENAME response "tempre.xml" ; proc soap in=request out=response url="http://wslite.strikeiron.com/censusinfolite01/censusinfolite.asmx" soapaction="http://www.wslite.strikeiron.com/getcensusinfoforzipcode" ; run; The result file is processed the same way, using an XMLMap

Get the service definition and parameters from the service documentation Find the definition for the data the service returns. Construct a URL containing: The Sevice URL Each Parameter specified &parametername=value Values must be encoded if they contain anything but letters an numbers The code is usually much simpler than SOAP

No standard return format. Common formats include: JSON Strings XML Images Read the documentation for each service SoapUI has tools for working with REST services as well

%let AddressVal = %qsysfunc(urlencode(1600 Pennsylvania Avenue NW)); %let CityVal = %qsysfunc(urlencode(washington)); %let StateVal = DC; %let url = %nrstr(http://local.yahooapis.com/mapsservice/v1/geocode) %nrstr(?appid=xxxxxxxxxxxx-) %nrstr(&street=)%superq(addressval) %nrstr(&city=)%superq(cityval) %nrstr(&state=)%superq(stateval); This Example uses the %put &url; Yahoo! Geocoding Service www.yahoo.com filename InURL url "%superq(url)" lrecl=4000; http://local.yahooapis.com/mapsservice/v1/geocode?appid=xxxxxxxxxxxxfilename OutXML "OutXML.xml"; data _null_; &street=1600%20pennsylvania%20avenue%20nw&city=washington&state=dc infile InURL length=len; input record $varying4000. len; file OutXML noprint notitles recfm=n; put record $varying4000. len; run;

<?xml version="1.0"?> <ResultSet xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xmlns="urn:yahoo:maps" xsi:schemalocation="urn:yahoo:maps http://api.local.yahoo.com/mapsservice/v1/geocoderesponse.xsd"> <Result precision="address"> <Latitude>38.898590</Latitude> <Longitude>-77.035971</Longitude> <Address>1600 Pennsylvania Ave NW</Address> <City>Washington</City> <State>DC</State> <Zip>20006</Zip> <Country>US</Country> </Result> </ResultSet> - <!-- ws01.ydn.gq1.yahoo.com uncompressed Fri Sep 25 10:06:25 PDT 2009 --> Can be easily read using an XMLMap and a XML Libname Reference

PROC HTTP Only Available in 9.2 phase 1 and later Handles many protocol issues Authentication Proxy Servers Specifying the Content Type Custom HTTP Headers GET and POST calls proc HTTP in=request out=response url=" http://www.soapserver.com/soapservice.ext ; run;

filename OutXML "OutXML.xml"; filename address "address.txt"; data _null_; file address; put 'appid=xxxxxxxxxxxx-' @; put '&street=1600 Pennsylvania Avenue NW' @; put '&city=washington' @; put '&state=dc'; run; PROC HTTP in=address out=outxml url="http://local.yahooapis.com/mapsservice/v1/geocode"; RUN;

Libname myxml XML XMLType = WSDL filename NWS url "http://www.weather.gov/forecasts/xml/soap_server/ndfdxmlserver.php?wsdl"; libname NWS XML92 xmltype=wsdl; proc datasets library=nws details; run; Brand new in 9.2 Phase 2 Allows direct calls to SOAP services via a LIBNAME reference. Very little documentation yet I can t get it to work

%let WorkDir = G:\PNWSUG\Papers\Soap\GoogleChart; filename in "&WorkDir\in"; filename out "&WorkDir\out.png"; data _null_; This Example uses the file in; put cht=v&chd=t:100,80,50,30,25,10,10&chs=500x500&chl= Google Chart API run; http://code.google.com/apis/chart/ proc http in=in out=out The first three url="http://chart.apis.google.com/chart?" values specify the relative sizes of three circles: A, B, and C. The method="post" fourth value specifies the area of A intersecting B. ct="application/x-www-form-urlencoded"; run; The fifth value specifies the area of A intersecting C. The sixth value specifies the area of B intersecting C. The seventh value specifies the area of A intersecting B intersecting C.

cht=p3&chd=t:30,10,60&chs=750x400&chl=apples P ears Bananas' Many more options can be found at http://code.google.com/apis/chart/

All of these public web services have Terms of Use agreements. Please read them before implementing an application that uses these services!

There are many different ways to consume web services from within base SAS. Depending SAS has made great improvements in its tools for doing this. They are continuing development in this area.

Curtis Mack Curtis.Mack@lgan.com Looking Glass Analytics www.lgan.com