На сайте Россвязи есть замечательный, периодически обновляющийся список, содержащий номерные ёмкости и телефонные компании, к которым эти диапазоны относятся. В данной статье описывается процедура получения и разбора этого файла с помощью апачевского 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(); Listregistry = 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 { // здесь проводится проверка строки на валидность и если // строка не валидна, выбрасывается эксепшн с номером строки }
Комментариев нет:
Отправить комментарий