Document processors » History » Version 1
Denis Kildishev, 12/08/2014 03:59 PM
1 | 1 | Denis Kildishev | h1. Document processors |
---|---|---|---|
2 | |||
3 | Requality содержит api для создания собственных обработчиков документов. Для реализации некоторого специфического обработчика можно воспользоваться интерфейсом IDocumentProcessor. При этом необходимо описать три метода: |
||
4 | setEncoding - устанавливающий кодировку |
||
5 | configure - вызываемый перед обработкой метод для настройки процессора. Например, может быть использован для запроса дополнительных параметров у пользователя. |
||
6 | process(String docId, TreeNode rootNode) — метод непосредственной обработки документа, параметры включают в себя идентификатор документа и элемент каталога требований |
||
7 | При использовании указанного подхода может осуществляться любая работа с документом, но при этом требуется описывать все связанные методы, в том числе связанные с загрузкой и выгрузкой содержимого документа. Для получения потока входных данных из документа с переданным идентификатором можно использовать пример: |
||
8 | Document doc = (Document) db.getNode(docQId); |
||
9 | String htmlName = doc.getResourceName(); |
||
10 | Reader reader = new InputStreamReader(doc.getResourceContent(htmlName), |
||
11 | encoding); |
||
12 | Имеется возможность использования реализации интерфейса скрывающего работу с файлом и предполагавшего работу с двумя потоками данных (DocumentProcessor) — на поток входных данных подается текущее содержимое документа, на поток выходных данных выводится модифицированная версия документа. Для импорта требований в таком случае будут добавлены теги соответствующие разметке требований. Стоит дополнительно отметить, что в случаях когда изменения документа не требуется, прочитанное содержимое должно быть записано в выходной поток иначе оно будет потеряно. |
||
13 | Для работы с классом необходимо наследовать класс и реализовать метод process(String docId, Reader reader, Writer writer, TreeNode rootNode) на вход которому подается идентификатор документа, Reader, Writer и элемент каталога требований для доступа к каталогу требований. Также при необходимости можно переопределить метод configure при необходимости дополнительных настроек перед обработкой. |
||
14 | |||
15 | На данный момент предусмотрено два наиболее часто применимых сценария работы с документами — автоматическое получение элементов каталога требований и изменение элементов каталога требований при переходе на новую версию документа. Для реализации обработчика согласно первому сценарию можно воспользоваться Simple API for XML(SAX) реализацией обработчика с набором предопределенных возможностей по работе с каталогом требований. При использовании данного подхода происходит последовательная обработка всех xml элементов в форме событий одного из трех основных видов, соответствующих обработке соответственно открывающего тега, закрывающего тега и фрагмента текста. |
||
16 | При этом потребуется реализовать наследника класса SAXDocumentParser и реализовать метод processEvent(XMLEvent event, XMLEventFactory eventFactory, XMLEventWriter writer, TreeNode rootNode). Метод соответствует обработке одного события парсером XMLEventFactory. Параметры: |
||
17 | event — обрабатываемое XMLEvent событие. Может соответствовать открытию тега(event.isStartElement()), закрытию тега(event.isEndElement()) или набору символов (event.isCharacters()) |
||
18 | eventFactory — фабрика для создания новых тегов или свойств |
||
19 | writer — интерфейс записи новой версии документа. При отсутствии изменений event должен быть записан во writer |
||
20 | rootNode — ссылка на элемент каталога требований |
||
21 | Для организации работы с документом также доступно несколько методов облегчающих запись в измененный вариант документа данных: |
||
22 | * startTag(String tagName,[ Map<String,String> attrib]) - открытие тега с именем tagName и набором свойств attrib в форме пар имя-значение. При этом свойства могут не указываться |
||
23 | * endTag(String tagName) — закрытие тега с именем tagName |
||
24 | * startRequirementFragment(Requirement req) - метод используемый для обозначения начала разметки фрагмента требования. Параметр — требование для которого размечется фрагмент. |
||
25 | * endRequirementFragment() - метод обозначающий окончание разметки фрагмента требования |
||
26 | * createRequirement([String name], [Requirement parent]) — метод для создания нового требования с указанным именем как потомка требования parent. Если параметр parent не указан то создает требование как потомка элемента /Requirements. Если не указан параметр name то используется автоматически сгенерированный идентификатор. Чтобы изменить имя требования следует впоследствии для требования последовательно выполнить операции .setName(String name) и .saveAttributes(). |
||
27 | * createComment(String description, [Requirement parent]) — метод для создания нового комментария, содержащего указанное в параметре description описание. Параметр parent — элемент для которого создается комментарий, при отсутствии параметра комментарий создается для элемента /Requirements |
||
28 | * getElement(String qualifiedId) — метод для получения элемента из каталога требований по пути к нему. Возвращает null если по указанному пути элемент не обнаружен |
||
29 | * getLocalTagName(XMLEvent event) — метод возвращающий имя тега для события если это возможно, иначе возвращающий null |
||
30 | * getTagAttribute(XMLEvent event, String attribName, [String defValue]) — метод возвращающий свойство открывающегося тега. Если свойства с указанным именем(attribName) не существует то возвращает значение defValue. Если последний не определен то возвращает null. |
||
31 | |||
32 | Как пример использования приведенных механизмов можно привести код добавления требований для заголовков H1: |
||
33 | <pre> |
||
34 | boolean headerStarted = false; |
||
35 | Requirement createdReq = null; |
||
36 | StringBuilder stored = new StringBuilder(); |
||
37 | void processEvent(XMLEvent event, XMLEventFactory eventFactory, XMLEventWriter writer, TreeNode rootNode){ |
||
38 | if(event.isStartEvent()){ |
||
39 | String tagName = getLocalTagName(event); |
||
40 | if(tagName.toLowerCase().equals(«h1»)){ |
||
41 | writer.add(event); |
||
42 | headerStarted = true; |
||
43 | stored.setLength(0); |
||
44 | createdReq = createRequirement(); |
||
45 | startRequirementFragment(createdReq); |
||
46 | }else |
||
47 | writer.add(event); |
||
48 | }else if(event.isEndEvent()){ |
||
49 | String tagName = getLocalTagName(event); |
||
50 | if(tagName.toLowerCase().equals(«h1»)) |
||
51 | { |
||
52 | String reqName = stored.toString(); |
||
53 | if(reqName.length>50) |
||
54 | reqName = reqName.substring(0,50); |
||
55 | createdReq.setName(reqName); |
||
56 | createdReq.saveAttributes(); |
||
57 | endRequirementFragment(createdReq); |
||
58 | createdComment(stored.toString(), createdReq); |
||
59 | } |
||
60 | writer.add(event); |
||
61 | }else if(event.isCharacters()){ |
||
62 | String content = event.asCharacters().getData(); |
||
63 | stored.append(content); |
||
64 | writer.add(event); |
||
65 | }else |
||
66 | writer.add(event); |
||
67 | } |
||
68 | </pre> |
||
69 | Другой задачей является реализация обработчика для переноса требований из одной версии документа в другую. В данном случае имеется возможность использовать класс DOMDocumentUpdateProcessor предоставляющий ряд возможностей для организации подобного процесса. |
||
70 | DOMDocumentUpdateProcessor также включает в себя несколько предопредленных методов для работы с каталогом требований, в том числе |
||
71 | * getLocation(TreeNode, String) для получения существующего Location по его UUID в строковом представлении |
||
72 | * getRequirementNode(TreeNode, String) для получения существующего Requirement по его Qualified Id или User Visible id. |
||
73 | * createLocation(Document, Node, int, Node, int, Document, Requirement) для создания нового фрагмента требования в документе. Содержит описание начала и конца выделения с возможностью указания точек до(POSITION_BEFORE) и после(POSITION_AFTER) выбранного элемента DOM модели. Содержит указание на целевой документ — обычно на требуемый обновления, то есть на соответствующий новой версии спецификации, и на целевое требование к которому будет добавлен создаваемый фрагмент |
||
74 | * addLocation(Document, Node, int, Node, int, String) для пометки фрагмента текста как принадлежащего существующему фрагменту с соответствующим id. |
||
75 | * createRequirement(TreeDB, String, Requirement) для создания требования-потомка выбранного требования. Устанавливает имя созданного элемента если оно было передано. TreeDB может быть получен у rootNode вызовом rootNode.getTreeDB() |
||
76 | * createRequirement(TreeDB, String) для создания требования-потомка /Requirements |
||
77 | Для наследования класса требуется определить метод process принимающего в виде параметров пути к документам, DOM модели «старого», то есть содержащего разметку в случае перехода на новую версию спецификации и «нового», в рассматриваемом случае не содержащего разметки, элемент каталога требований. Метод предполагает наличие возвращаемого значения в виде DOM модели, которая будет записана в содержимое «нового» документа. |