function [textData, cats, resumptionToken] = parseArXivRecords(url)
%parseArxivRecords Parse XML from ArXiv API
%   textData = parseArXivRecords(url) extracts the abstract text from the
%   records in the specified query URL.
%
%   [textData, cats] = parseArXivRecords(url) also returns the arXiv
%   categories for each record.
%
%   [textData, cats, resumptionToken] = parseArXivRecords(url) also
%   returns the resumption token required for repeated calls to the arXiv
%   API.

% Save XML to temporary file.
filename = fullfile(tempdir,"arxivData.xml");
options = weboptions('Timeout',160);
websave(filename,url,options);

% Parse XML code.
data = readstruct(filename,'StructNodeName','ListRecords');

% Remove empty records.
idx = arrayfun(@(record) isstruct(record.metadata),data.record);
data.record = data.record(idx);

% Extract text and categories.
textData = arrayfun(@(record) record.metadata.arXiv.abstract,data.record)';
cats = arrayfun(@(record) split(record.metadata.arXiv.categories),data.record,'UniformOutput',false)';

% Extract resumption token.
resumptionToken = data.resumptionToken.Text;

end