Project

General

Profile

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 модели, которая будет записана в содержимое «нового» документа.