2012-06-04 5 views
4

Я построил парсер GPX с использованием XML-conduit и имел проблемы с чрезмерно подробным и хрупким кодом для идентификации элементов и пропуска нежелательных тегов.Хрупкий и подробный код с использованием xml-conduit

Определение элементов (незначительное раздражение)

Я явно пренебрегая пространство имен путем сравнения только nameLocalName сек. Я предполагаю, что правильным способом является жесткое кодирование правильного пространства имен в программе и наличие вспомогательных конструкций для моих имен элементов для сравнения в функциях tag*? Это немного раздражает, так как я должен поддерживать по крайней мере два разных пространства имен (GPX 1.1 и 1.0), которые достаточно схожи, что они не требуют изменений кода для моих целей.

Досрочных элементы

GPX является великоватым и множество пользовательских расширений больше. Поскольку инструмент, который я создаю, нуждается в ограниченной информации, я решил игнорировать определенные теги вместе со всеми их подэлементами. Например:

<trkpnt lat="45.19843" lon="-122.428"> 
    <ele>4</ele> 
    <time>...</time> 
    <extensions> 
     ... 
    </extensions> 
</trkpnt> 

Игнорирования extensions и подобные метки с многочисленными субэлементами я сделал мойку, что бы потребить элементы до конца элемента Event:

skipTagAndContents :: (MonadThrow m) => Text -> Sink Event m (Maybe()) 
skipTagAndContents n = tagPredicate ((== n) . nameLocalName) 
            ignoreAttrs 
            (const $ many (skipElements n) >> return()) 

skipElements t = do 
     x <- await 
     case x of 
       Just (EventEndElement n) | nameLocalName n == t -> Done x Nothing 
       Nothing -> Done x Nothing 
       _ -> return (Just()) 

Кажется, там должна быть tag* вариант, сделаю это для меня (преуспеть, если не будут поглощены все дети), но тот факт, что я не предлагаю, чтобы я пропустил простой комбинатор или должен отправить патч - что это?

ответ

2

Если вы вообще не используете пространства имен, может быть проще всего просто удалить их полностью, используя что-то вроде Data.Conduit.List.map stripNamespace.

Честно говоря, я действительно не использую потоковый интерфейс, который часто сам; почти вся моя работа связана с DOM (Text.XML) или интерфейсами курсора. Поэтому вполне возможно, что отсутствуют комминанты. Но в этом случае я считаю, что вы можете значительно упростить реализацию, так как tagPredicate не должен позволять внутреннему Sink читать за конец элемента. Таким образом, вы можете переписать skipTagAndContents как:

tagPredicate ((== n) . nameLocalName) ignoreAttrs (const Data.Conduit.List.sinkNull) 

Вы должны проверить, что прежде всего сбросив его, я мог бы вспомнить некоторые детали интерфейса потокового некорректна.

+0

У меня был аналогичный код, и он приводит к ошибкам, таким как 'XmlException {xmlErrorMessage =" Ожидаемый конечный тег для: Name {nameLocalName = \ "metadata \", nameNamespace = Just \ "http://www.topografix.com/ GPX/1/1 \ ", namePrefix = Nothing}", xmlBadInput = Nothing} '. Поэтому на данный момент я буду придерживаться своей реализации, в которой явно указано конечный тег. ПолосаNamespace очистит что-то, хотя - спасибо! –