На сайте Россвязи есть замечательный, периодически обновляющийся список, содержащий номерные ёмкости и телефонные компании, к которым эти диапазоны относятся. В данной статье описывается процедура получения и разбора этого файла с помощью апачевского HttpClient и обычного SAX парсера.
- Скачиваем html со списком кодов
Для этого вполне подойдет org.apache.http.impl.client.DefaultHttpClient
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpget = new HttpGet("http://rossvyaz.ru/docs/articles/DEF-9x.html");
HttpResponse resp = client.execute(httpget);
if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
InputStream is = resp.getEntity().getContent();
List registry = new ArrayList();
parseHTML(is, registry);
}
Но вот незадача, контент сжат gzip'ом. В принципе это даже неплохо, уменьшается время загрузки и сетевой трафик, так что просто добавим поддержку gzip в HttpClient. Делается это путем добавления перехватчиков на запрос и ответ:
private DefaultHttpClient prepareHttpClient() {
DefaultHttpClient client = new DefaultHttpClient();
client.addRequestInterceptor(new HttpRequestInterceptor() {
public void process(
final HttpRequest request,
final HttpContext context) throws HttpException, IOException {
if (!request.containsHeader("Accept-Encoding")) {
request.addHeader("Accept-Encoding", "gzip");
}
}
});
client.addResponseInterceptor(new HttpResponseInterceptor() {
public void process(
final HttpResponse response,
final HttpContext context) throws HttpException, IOException {
HttpEntity entity = response.getEntity();
if (entity != null) {
Header ceheader = entity.getContentEncoding();
if (ceheader != null) {
HeaderElement[] codecs = ceheader.getElements();
for (int i = 0; i < codecs.length; i++) {
if (codecs[i].getName().equalsIgnoreCase("gzip")) {
response.setEntity(
new GzipDecompressingEntity(response.getEntity()));
return;
}
}
}
}
}
});
return client;
}
Теперь осталось разобрать полученный html и вытащить из него DEF коды.
- Парсим полученный html
Воспользуется стандартным потоковым java SAX парсером (javax.xml.stream.XMLEventReader), поскольку полученный файл большой, и к тому же является невалидным XML файлом, так что придется произвести небольшие ухищрения, чтобы его разобрать. Разбор производится "на лету", то есть начинается уже в процессе скачивания html, за счет чего достигается приличная скорость при небольшом потреблении памяти. Весь процесс занимает порядка трех секунд.
static final String TR = "tr";
static final String TD = "td";
...
private void parseHTML(InputStream is, List<DEFCode> result) {
try {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLEventReader eventReader = inputFactory.createXMLEventReader(is, "windows-1251");
String[] buff = new String[6];
int count = 0;
int ind = 0;
while (eventReader.hasNext()) {
try {
XMLEvent event = eventReader.nextEvent();
if (event.isStartElement()) {
StartElement startElement = event.asStartElement();
// start new row
if (TR.equals(startElement.getName().getLocalPart())) {
buff = new String[6];
count++;
ind = 0;
}
if (TD.equals(event.asStartElement().getName().getLocalPart())) {
event = eventReader.nextEvent();
buff[ind++] = event.asCharacters().getData();
continue;
}
}
if (event.isEndElement()) {
EndElement endElement = event.asEndElement();
if (TR.equals(endElement.getName().getLocalPart())) {
if(count != 1){ // пропускаем первую строку с заголовком
result.add(validateRow(count, buff));
}
}
}
} catch (XMLStreamException e) { // вероятнее всего это незакрытый тег, игнорируем ошибку
logger.error("skip error");
} catch(Exception ex){ // вероятнее всего файл просто закончился, завершаем обработку
logger.error("skip error, break");
break;
}
}
eventReader.close();
} catch (XMLStreamException e) { // что-то не так с кодировкой или структурой файла
e.printStackTrace();
}
}
private DEFCode validateRow(int counter, String[] nextLine) throws ValidationException {
// здесь проводится проверка строки на валидность и если
// строка не валидна, выбрасывается эксепшн с номером строки
}
Комментариев нет:
Отправить комментарий