std/parsexml
ИсточникРедактироватьЭтот модуль реализует простой высокопроизводительный парсер XML / HTML. Поддерживается только кодировка UTF-8. Парсер разработан с некоторой корректировкой ошибок, так что даже большая часть «неправильного HTML», найденного в Интернете, может быть обработана им. Примечание: Этот парсер не проверяет, что каждому <tag> соответствует </tag>! Эти проверки должны быть реализованы кодом клиента по разным причинам:
- Старый HTML содержит теги без закрывающих тегов:
<br>например. - HTML-теги регистронезависимы, XML-теги регистрозависимы. Поскольку эта библиотека может анализировать оба, только клиент знает, какой сравнения использовать.
- Таким образом, проверки было бы очень трудно реализовать должным образом с небольшими преимуществами, особенно учитывая, что их просто реализовать в клиенте. Клиент должен использовать процедуру
errorMsgExpectedдля генерации приятного сообщения об ошибке, которое соответствует другим сообщениям об ошибках, создаваемым этой библиотекой.
Пример 1: Извлечение заголовка HTML
Файл examples/htmltitle.nim демонстрирует, как использовать XML-парсер для выполнения простой задачи: определения заголовка HTML-документа.
# Example program to show the parsexml module
# This program reads an HTML file and writes its title to stdout.
# Errors and whitespace are ignored.
import std/[os, streams, parsexml, strutils]
if paramCount() < 1:
quit("Usage: htmltitle filename[.html]")
var filename = addFileExt(paramStr(1), "html")
var s = newFileStream(filename, fmRead)
if s == nil: quit("cannot open the file " & filename)
var x: XmlParser
open(x, s, filename)
while true:
x.next()
case x.kind
of xmlElementStart:
if cmpIgnoreCase(x.elementName, "title") == 0:
var title = ""
x.next() # skip "<title>"
while x.kind == xmlCharData:
title.add(x.charData)
x.next()
if x.kind == xmlElementEnd and cmpIgnoreCase(x.elementName, "title") == 0:
echo("Title: " & title)
quit(0) # Success!
else:
echo(x.errorMsgExpected("/title"))
of xmlEof: break # end of file reached
else: discard # ignore other events
x.close()
quit("Could not determine title!") Пример 2: Извлечение всех HTML-ссылок
Файл examples/htmlrefs.nim демонстрирует, как использовать XML-парсер для выполнения другой простой задачи: определения всех ссылок, содержащихся в HTML-документе.
# Example program to show the new parsexml module
# This program reads an HTML file and writes all its used links to stdout.
# Errors and whitespace are ignored.
import std/[os, streams, parsexml, strutils]
proc `=?=` (a, b: string): bool =
# little trick: define our own comparator that ignores case
return cmpIgnoreCase(a, b) == 0
if paramCount() < 1:
quit("Usage: htmlrefs filename[.html]")
var links = 0 # count the number of links
var filename = addFileExt(paramStr(1), "html")
var s = newFileStream(filename, fmRead)
if s == nil: quit("cannot open the file " & filename)
var x: XmlParser
open(x, s, filename)
next(x) # get first event
block mainLoop:
while true:
case x.kind
of xmlElementOpen:
# the <a href = "xyz"> tag we are interested in always has an attribute,
# thus we search for ``xmlElementOpen`` and not for ``xmlElementStart``
if x.elementName =?= "a":
x.next()
if x.kind == xmlAttribute:
if x.attrKey =?= "href":
var link = x.attrValue
inc(links)
# skip until we have an ``xmlElementClose`` event
while true:
x.next()
case x.kind
of xmlEof: break mainLoop
of xmlElementClose: break
else: discard
x.next() # skip ``xmlElementClose``
# now we have the description for the ``a`` element
var desc = ""
while x.kind == xmlCharData:
desc.add(x.charData)
x.next()
echo(desc & ": " & link)
else:
x.next()
of xmlEof: break # end of file reached
of xmlError:
echo(errorMsg(x))
x.next()
else: x.next() # skip other events
echo($links & " link(s) found!")
x.close() Импорты
- strutils, lexbase, streams, unicode, os
Типы
XmlErrorKind = enum errNone, ## no error errEndOfCDataExpected, ## ``]]>`` expected errNameExpected, ## name expected errSemicolonExpected, ## ``;`` expected errQmGtExpected, ## ``?>`` expected errGtExpected, ## ``>`` expected errEqExpected, ## ``=`` expected errQuoteExpected, ## ``"`` or ``'`` expected errEndOfCommentExpected, ## ``-->`` expected errAttributeValueExpected ## non-empty attribute value expected
- перечисление, которое перечисляет все возможные ошибки Источник Редактировать
XmlEventKind = enum xmlError, ## an error occurred during parsing xmlEof, ## end of file reached xmlCharData, ## character data xmlWhitespace, ## whitespace has been parsed xmlComment, ## a comment has been parsed xmlPI, ## processing instruction (``<?name something ?>``) xmlElementStart, ## ``<elem>`` xmlElementEnd, ## ``</elem>`` xmlElementOpen, ## ``<elem xmlAttribute, ## ``key = "value"`` pair xmlElementClose, ## ``>`` xmlCData, ## ``<![CDATA[`` ... data ... ``]]>`` xmlEntity, ## &entity; xmlSpecial ## ``<! ... data ... >``
- перечисление всех событий, которые могут произойти при анализе Источник Редактировать
XmlParseOption = enum reportWhitespace, ## report whitespace reportComments, ## report comments allowUnquotedAttribs, ## allow unquoted attribute values (for HTML) allowEmptyAttribs ## allow empty attributes (without explicit value)
- параметры для XML-парсера Источник Редактировать
XmlParser = object of BaseLexer
- объект парсера. Источник Редактировать
Процедуры
proc close(my: var XmlParser) {.inline, ...raises: [IOError, OSError], tags: [WriteIOEffect], forbids: [].}- закрывает парсер
myи связанный с ним входной поток. Источник Редактировать proc errorMsg(my: XmlParser): string {....raises: [ValueError], tags: [], forbids: [].}- возвращает полезное сообщение об ошибке для события
xmlErrorИсточник Редактировать proc errorMsg(my: XmlParser; msg: string): string {....raises: [ValueError], tags: [], forbids: [].}- возвращает сообщение об ошибке с текстом
msgв том же формате, что и другие сообщения об ошибках Источник Редактировать proc errorMsgExpected(my: XmlParser; tag: string): string {. ...raises: [ValueError], tags: [], forbids: [].}- возвращает сообщение об ошибке «<tag> ожидается» в том же формате, что и другие сообщения об ошибках Источник Редактировать
proc getColumn(my: XmlParser): int {.inline, ...raises: [], tags: [], forbids: [].}- получить текущую колонку, до которой добрался парсер. Источник Редактировать
proc getFilename(my: XmlParser): string {.inline, ...raises: [], tags: [], forbids: [].}- получить имя файла, обрабатываемого парсером. Источник Редактировать
proc getLine(my: XmlParser): int {.inline, ...raises: [], tags: [], forbids: [].}- получить текущую строку, до которой добрался парсер. Источник Редактировать
proc kind(my: XmlParser): XmlEventKind {.inline, ...raises: [], tags: [], forbids: [].}- возвращает текущий тип события для XML-парсера Источник Редактировать
proc next(my: var XmlParser) {....raises: [IOError, OSError], tags: [ReadIOEffect], forbids: [].}- извлекает первое/следующее событие. Это управляет парсером. Источник Редактировать
proc open(my: var XmlParser; input: Stream; filename: string; options: set[XmlParseOption] = {}) {....raises: [IOError, OSError], tags: [ReadIOEffect], forbids: [].}- инициализирует парсер с входным потоком.
Filenameиспользуется только для приятных сообщений об ошибках. Поведение парсера можно контролировать с помощью параметраoptions: ЕслиoptionsсодержитreportWhitespace, то маркер пробела отображается как событиеxmlWhitespace. ЕслиoptionsсодержитreportComments, то маркер комментария отображается как событиеxmlComment. Источник Редактировать proc rawData(my: var XmlParser): lent string {.inline, ...raises: [], tags: [], forbids: [].}- возвращает исходную строку 'data' по ссылке. Это используется только для ускорения работы. Источник Редактировать
proc rawData2(my: var XmlParser): lent string {.inline, ...raises: [], tags: [], forbids: [].}- возвращает исходную вторую строку 'data' по ссылке. Это используется только для ускорения работы. Источник Редактировать
Шаблоны
template attrKey(my: XmlParser): string
- возвращает ключ атрибута для события
xmlAttributeВызывает утверждение в режиме отладки, еслиmy.kindне равноxmlAttribute. В режиме релиз это не вызовет ошибку, но возвращаемое значение будет недействительным. Исходный код Изменить template attrValue(my: XmlParser): string
- возвращает значение атрибута для события
xmlAttributeВызывает утверждение в режиме отладки, еслиmy.kindне равноxmlAttribute. В режиме релиз это не вызовет ошибку, но возвращаемое значение будет недействительным. Исходный код Изменить template charData(my: XmlParser): string
- возвращает данные символов для событий:
xmlCharData,xmlWhitespace,xmlComment,xmlCData,xmlSpecialВызывает утверждение в режиме отладки, еслиmy.kindне является одним из этих событий. В режиме релиз это не вызовет ошибку, но возвращаемое значение будет недействительным. Исходный код Изменить template elementName(my: XmlParser): string
- возвращает имя элемента для событий:
xmlElementStart,xmlElementEnd,xmlElementOpenВызывает утверждение в режиме отладки, еслиmy.kindне является одним из этих событий. В режиме релиз это не вызовет ошибку, но возвращаемое значение будет недействительным. Исходный код Изменить template entityName(my: XmlParser): string
- возвращает имя сущности для события:
xmlEntityВызывает утверждение в режиме отладки, еслиmy.kindне равноxmlEntity. В режиме релиз это не вызовет ошибку, но возвращаемое значение будет недействительным. Исходный код Изменить template piName(my: XmlParser): string
- возвращает имя инструкции обработки для события
xmlPIВызывает утверждение в режиме отладки, еслиmy.kindне равноxmlPI. В режиме релиз это не вызовет ошибку, но возвращаемое значение будет недействительным. Исходный код Изменить template piRest(my: XmlParser): string
- возвращает остальную часть инструкции обработки для события
xmlPIВызывает утверждение в режиме отладки, еслиmy.kindне равноxmlPI. В режиме релиз это не вызовет ошибку, но возвращаемое значение будет недействительным. Исходный код Изменить
© 2006–2024 Andreas Rumpf
Licensed under the MIT License.
https://nim-lang.org/docs/parsexml.html