#' List Items in API Database
#'
#' This function returns a data.frame listing items in Xaxis for Publishers.
#' Only the most important details are returned. Certain search criteria may
#' be added to the request to narrow the results returned.
#'
#' @usage oas_list(credentials,
#' request_type=c('Advertiser', 'AdvertiserCategory', 'Affiliate',
#' 'Agency', 'CampaignGroup', 'CompanionPosition',
#' 'CompetitiveCategory', 'ConversionProcess',
#' 'CreativeType',
#' 'Event', 'InsertionOrder', 'Notification',
#' 'Page', 'Product', 'RichMediaTemplate',
#' 'SalesPerson', 'Section', 'Site',
#' 'SiteGroup', 'Transaction', 'Position',
#' 'Keyword', 'Keyname', 'Publisher',
#' 'Campaign',
#' 'CreativeTarget', 'Creative'),
#' campaign_id = NULL,
#' parentcampaign_id = NULL,
#' search_criteria_attributes = c(pageIndex="-1", pageSize="1000"),
#' search_criteria = NULL, verbose = FALSE)
#' @concept api list
#' @importFrom methods as
#' @include utils.R
#' @param credentials a character string as returned by \link{oas_build_credentials}
#' @param request_type a character string in one of the supported
#' object types for the API database list action
#' @param campaign_id a character string exactly matching the ID of a campaign. This parameter
#' is only utilized for request type "Notification" because Campaign Notifications cannot be
#' listed/searched across Campaigns. The Campaign Id must be specified exactly with no wildcard
#' characters. Thus, CampaignId is not part of the SearchCriteria element and there is a
#' specialized AdXML structure required for LIST Notification.
#' @param parentcampaign_id a character string exactly matching the ID of a campaign. This parameter
#' is only utilized for a request type "CreativeTarget" because Creative Targets cannot be listed/searched
#' across Campaigns. The ParentCampaignId must be used and exact attribute has to be set to "true" .
#' @param search_criteria_attributes a named character vector of attributes
#' to add to the SearchCriteria node. Acceptable parameters are pageSize and
#' pageIndex to support paginated requests. Default pageSize for request types Campaign,
#' CampaignGroup, and Creatives is: 30,000, while all others have a default pageSize of 1000.
#' @param search_criteria an XML document specifying the children to be
#' added to the SearchCriteria Node in the request
#' @param verbose a boolean indicating whether to print the request XML as a message
#' @return A \code{data.frame} listing all objects of the specified type that
#' also met the supplied search criteria
#' @note Most objects have a unique list of searchable criteria. Please consult the
#' API documentation for a complete coverage.
#' Here are the options for Campaigns:
#' \itemize{
#' \item Type: 'RM' for regular campaign, 'CLT' for CLT Campaign, 'ALL' for whole campaign
#' \item Status: Search by Campaign Status. See Codes to Use in Single Character Fields
#' \item Id: Search by Campaign ID. If "exact" attribute is "true", API returns exact campaign
#' having defined value. Otherwise, API returns all campaigns containing defined value in campaign ID.
#' \item Url: Search by Scheduled Page URL
#' \item SectionId: Search by Scheduled Section ID
#' \item AdvertiserId: Search by Scheduled Advertiser ID
#' \item AgencyId: Search by associated Agency ID
#' \item CampaignGroupId: Search by associated Campaign Group ID
#' \item StartDate: Search by Start Date. Date value with YYYY-MM-DD format is required.
#' "condition" attribute can be defined among EQ, GE,LE,GT and LT. Multiple StartDate can be used.
#' \item EndDate: Search by End Date. Date value with YYYY-MM-DD format is required.
#' "condition" attribute can be defined among EQ, GE,LE,GT and LT. Multiple StartDate can be used.
#' \item WhenCreated: Search by When the campaign was created. Date value with YYYY-MM-DD hh:mm:ss
#' format is required( Time part is optional). "condition" attribute can be defined among EQ,
#' GE,LE,GT and LT. Multiple WhenCreated can be used.
#' \item WhenModified: Search by When the campaign was modified. Date value with YYYY-MM-DD hh:mm:ss
#' format is required( Time part is optional). "condition" attribute can be defined among EQ,
#' GE,LE,GT and LT. Multiple WhenCreated can be used.
#' \item PriorityLevel: Search by Campaign Priority Level. Available value is 1 to 20.
#' "condition" attribute can be defined among EQ, GE,LE,GT and LT. Multiple PriorityLevel can be used.
#' \item Completion: Search by Completion Type.
#' See Codes to Use in Single Character Fields for available abbreviation code.
#' \item Reach: Search by Reach Type.
#' See Codes to Use in Single Character Fields for available abbreviation code.
#' \item PurchaseOrder: Search by Purchase Order #.
#' "condition" attribute can be defined among EQ, GE,LE,GT,LT and also LK
#' \item InsertionOrderId: Search by associated Insertion Order ID
#' \item CampaignManager: Search by associated CampaignManager
#' }
#' The condition attribute values of "EQ, GE, LE, GT, LT" stand for equality operators
#' @examples
#' \dontrun{
#' my_credentials <- build_credentials('myaccount',
#' 'myusername',
#' 'mypassword')
#' list_of_sites <- oas_list(credentials=my_credentials, request_type='Site')
#' list_of_100_pages <- oas_list(credentials=my_credentials, request_type='Page',
#' search_criteria_attributes = c(pageSize="100"))
#' list_campaigns <- oas_list(credentials=my_credentials, request_type='Campaign',
#' search_criteria_attributes = c(pageSize="100"),
#' search_criteria=list(newXMLNode("EndDate",
#' attrs = c(condition = "GT"),
#' '2014-12-31')))
#' list_by_criteria <- oas_list(credentials=my_credentials,
#' request_type='Page',
#' search_criteria_attributes = c(pageSize="100"),
#' search_criteria=list(newXMLNode("Domain", "mySite"),
#' newXMLNode("Url", "001"),
#' newXMLNode("SectionId", "Ar%ves"),
#' newXMLNode("SiteId", "ApiSite"),
#' newXMLNode("Description", "My Page"),
#' newXMLNode("LocationKey", "7"),
#' newXMLNode("WhenCreated",
#' attrs = c(condition = "GT"),
#' '2014-12-31'),
#' newXMLNode("WhenModified",
#' attrs = c(condition = "GT"),
#' '2013-12-31')))
#' }
#' @export
oas_list <- function(credentials,
request_type=c('Advertiser', 'AdvertiserCategory', 'Affiliate',
'Agency', 'CampaignGroup', 'CompanionPosition',
'CompetitiveCategory', 'ConversionProcess',
'CreativeType',
'Event', 'InsertionOrder', 'Notification',
'Page', 'Product', 'RichMediaTemplate',
'SalesPerson', 'Section', 'Site',
'SiteGroup', 'Transaction', 'Position',
'Keyword', 'Keyname', 'Publisher',
'Campaign',
'CreativeTarget', 'Creative'),
campaign_id = NULL,
parentcampaign_id = NULL,
search_criteria_attributes = c(pageIndex="-1", pageSize="1000"),
search_criteria = NULL, verbose = FALSE){
paginate <- FALSE
if(!('pageIndex' %in% names(search_criteria_attributes)) |
search_criteria_attributes['pageIndex'] == "-1"){
search_criteria_attributes['pageIndex'] <- "1"
paginate <- TRUE
} else {
if(!('pageSize' %in% names(search_criteria_attributes))){
stop('Must supply a pageSize if using the pageIndex search criteria attribute')
}
}
# both paging parameters must be specified
stopifnot(all(c('pageIndex', 'pageSize') %in% names(search_criteria_attributes)))
adxml_node <- newXMLNode("AdXML")
request_node <- newXMLNode("Request", attrs = c(type = request_type),
parent = adxml_node)
if (request_type %in% c('Campaign', 'Notification', 'InsertionOrder', 'CreativeTarget', 'Creative')){
database_node <- newXMLNode(request_type, attrs = c(action = "list"),
parent = request_node)
} else {
database_node <- newXMLNode("Database", attrs = c(action = "list"),
parent = request_node)
}
if(request_type == 'Notification'){
if(is.null(campaign_id)){
stop('campaign_id argument must be specified when listing notifications')
} else {
campaign_node <- newXMLNode("CampaignId", campaign_id, parent = database_node)
}
}
if(request_type == 'CreativeTarget'){
if(is.null(parentcampaign_id)){
stop('parentcampaign_id argument must be specified when listing creative targets')
} else {
campaign_node <- newXMLNode("ParentCampaignId",
attrs = c(exact="true"),
parentcampaign_id,
parent = database_node)
}
}
search_criteria_node <- newXMLNode("SearchCriteria",
attrs=search_criteria_attributes,
parent = database_node)
for (node in search_criteria){
addChildren(search_criteria_node, node)
}
adxml_string <- as(adxml_node, "character")
xmlBody <- request_builder(credentials=credentials,
adxml_request=adxml_string)
if(verbose){
message(adxml_string)
}
result <- perform_request(xmlBody)
parsed_result <- list_result_parser(xmlBody = xmlBody,
paginate = paginate,
result_text = result$text$value(),
request_type = request_type,
verbose = verbose)
return(parsed_result)
}
#' List Code Items from API Database
#'
#' This function returns a data.frame listing codes associated to a particular
#' field on an object in Xaxis for Publishers. Certain search criteria may
#' be added to the request to narrow the results returned. This function is very similar to
#' \code{list_request}; however it is specifically for returning code maps.
#'
#' @usage oas_list_code(credentials,
#' code_type=c('Bandwidth', 'Browser', 'BrowserV', 'Continent',
#' 'Country', 'City', 'State', 'DMA', 'MSA',
#' 'EventType', 'HourOfDay', 'WeekDay',
#' 'Omniture', 'OS', 'Position',
#' 'TopDomain', 'Zone', 'Carrier',
#' 'DeviceGroup', 'Device', 'Manufacturer'),
#' search_criteria_attributes = c(pageIndex="-1", pageSize="1000"),
#' search_criteria = NULL, verbose = FALSE)
#' @concept api list
#' @include utils.R
#' @param credentials a character string as returned by \link{oas_build_credentials}
#' @param code_type a character string in one of the supported
#' code types for the API database list action
#' @param search_criteria_attributes a named character vector of attributes
#' to add to the SearchCriteria node. Acceptable parameters are pageSize and
#' pageIndex to support paginated requests. Default pageSize for request types Campaign,
#' CampaignGroup, and Creatives is: 30,000, while all others have a default pageSize of 1000.
#' @param search_criteria an XML document specifying the children to be
#' added to the SearchCriteria Node in the request
#' @param verbose a boolean indicating whether to print the request XML as a message
#' @return A \code{data.frame} listing all objects of the specified type that
#' also met the supplied search criteria
#' @examples
#' \dontrun{
#' my_credentials <- build_credentials('myaccount',
#' 'myusername',
#' 'mypassword')
#'
#' country_criteria_node = newXMLNode("Country", parent = search_criteria_node)
#' country_code_node = newXMLNode("Code", "US", parent = country_criteria_node)
#' us_city_codes <- oas_list_code(credentials=my_credentials, code_type='City',
#' search_criteria_attributes = c(pageSize="20000"),
#' search_criteria=list(country_code_node))
#' }
#' @export
oas_list_code <- function(credentials,
code_type=c('Bandwidth', 'Browser', 'BrowserV', 'Continent',
'Country', 'City', 'State', 'DMA', 'MSA',
'EventType', 'HourOfDay', 'WeekDay',
'Omniture', 'OS', 'Position',
'TopDomain', 'Zone', 'Carrier',
'DeviceGroup', 'Device', 'Manufacturer'),
search_criteria_attributes = c(pageIndex="-1", pageSize="1000"),
search_criteria = NULL, verbose = FALSE){
code_type <- if(code_type=='DMA') 'Dma' else code_type
code_type <- if(code_type=='MSA') 'Msa' else code_type
paginate <- FALSE
if(!('pageIndex' %in% names(search_criteria_attributes)) |
search_criteria_attributes['pageIndex'] == "-1"){
search_criteria_attributes['pageIndex'] <- "1"
paginate <- TRUE
} else {
if(!('pageSize' %in% names(search_criteria_attributes))){
stop('Must supply a pageSize if using the pageIndex search criteria attribute')
}
}
# both paging parameters must be specified
stopifnot(all(c('pageIndex', 'pageSize') %in% names(search_criteria_attributes)))
adxml_node <- newXMLNode("AdXML")
request_node <- newXMLNode("Request", attrs = c(type = code_type),
parent = adxml_node)
if(code_type %in% c('Carrier', 'DeviceGroup', 'Device', 'Manufacturer')){
database_node <- newXMLNode("Database", attrs = c(action = "selectedlist"),
parent = request_node)
} else {
database_node <- newXMLNode("Database", attrs = c(action = "list"),
parent = request_node)
}
search_criteria_node <- newXMLNode("SearchCriteria",
attrs=search_criteria_attributes,
parent = database_node)
for (node in search_criteria){
addChildren(search_criteria_node, node)
}
adxml_string <- as(adxml_node, "character")
xmlBody <- request_builder(credentials=credentials,
adxml_request=adxml_string)
if(verbose){
message(adxml_string)
}
result <- perform_request(xmlBody)
parsed_result <- list_result_parser(xmlBody = xmlBody,
paginate = paginate,
result_text = result$text$value(),
request_type = code_type,
verbose = verbose)
return(parsed_result)
}
doc_result_converter <- function(result_text){
doc <- xmlTreeParse(result_text, asText=T)
result_body <- xmlToList(doc)$Body.OasXmlRequestResponse.result
result_body_doc <- xmlParse(result_body)
# Check for error
errorcode <- NA
errormessage <- NA
try(errorcode <- xmlAttrs(getNodeSet(result_body_doc,
"//Exception")[[1]], 'errorCode'), silent = T)
try(errormessage <- xmlValue(getNodeSet(result_body_doc,
"//Exception")[[1]]), silent = T)
if(!is.na(errorcode) && !is.na(errormessage)){
stop(paste0('errorCode ', errorcode, ": ", errormessage))
}
return(result_body_doc)
}
#' Parse List Recordsets with Pagination Support
#'
#' This function takes an initial API return message with parameters
#' on how to paginate and parse the message and subsequent calls if needed
#'
#' @usage list_result_parser(xmlBody, paginate, result_text, request_type, verbose = FALSE)
#' @concept api list
#' @include utils.R
#' @importFrom plyr rbind.fill
#' @param xmlBody a character string that appears as XML of the original request
#' sent over to the API
#' @param paginate a \code{logical} indicating whether pagination is needed
#' @param result_text a character string that appears as XML as
#' returned by an API call
#' @param request_type a character string in one of the supported
#' object types for the API database list action
#' @param verbose a boolean indicating whether to print the request XML as a message
#' @return A \code{data.frame} listing all objects of the specified type that
#' also met the supplied search criteria
list_result_parser <- function(xmlBody, paginate, result_text, request_type,
verbose = FALSE){
# pull out the results and format as XML
# this takes some redundant steps to get the AdXML recognized as XML for parsing
result_body_doc <- doc_result_converter(result_text)
# check the total number of matching entries because we might need to
# paginate through other resultsets
total_n <- as.integer(xmlAttrs(getNodeSet(result_body_doc,
"//List")[[1]])['totalNumberOfEntries'])
# some requests will not return a total_n where pagination is not needed
total_n <- if(!is.finite(total_n)) 0 else total_n
number_of_rows <- as.integer(xmlAttrs(getNodeSet(result_body_doc,
"//List")[[1]])['numberOfRows'])
pageSize <- as.integer(xmlAttrs(getNodeSet(result_body_doc,
"//List")[[1]])['pageSize'])
result_df <- xmlToDataFrame(nodes =
getNodeSet(result_body_doc,
paste0("//List/", request_type)),
collectNames = F, stringsAsFactors = F)
result_dfs <- list()
result_dfs[[1]] <- result_df
if(paginate & total_n > number_of_rows){
batches_quotient <- total_n %/% pageSize
batches_remainder <- total_n %% pageSize
total_calls <- if(batches_remainder == 0) batches_quotient else batches_quotient + 1
if(total_calls >= 2){
for (i in 2:total_calls){
# sub in new pageIndex and request
xmlBody_next_page <- gsub('pageIndex="[0-9]+"', sprintf('pageIndex="%s"', i), xmlBody)
result <- exponential_backoff_retry(perform_request(xmlBody_next_page))
# pull out the XML as text
result_text <- result$text$value()
result_body_doc <- doc_result_converter(result_text)
result_df <- xmlToDataFrame(nodes =
getNodeSet(result_body_doc,
paste0("//List/", request_type)),
collectNames = F, stringsAsFactors = F)
result_dfs[[i]] <- result_df
}
}
}
final_df <- rbind.fill(result_dfs)
return(final_df)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.