Index: tests_py2ttl/test_data/mapping_dict.xml =================================================================== --- tests_py2ttl/test_data/mapping_dict.xml (revision 68) +++ tests_py2ttl/test_data/mapping_dict.xml (revision 69) @@ -1,242 +1,236 @@ <?xml version="1.0" encoding="utf-8"?> <root> <dict> <ontology> <project_name type="str">tln</project_name> - <project_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#</project_uri> + <project_uri type="URIRef">http://www.nie.org/ontology/nietzsche#</project_uri> + <ontology_file type="str">./tln-ontology_autogenerated.ttl</ontology_file> </ontology> <classes> <ArchivalManuscriptUnity> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#ArchivalManuscriptUnity</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#ArchivalManuscriptUnity</class_uri> <properties> - <title type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTitle</title> - <manuscript_type type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasManuscriptType</manuscript_type> - <pages type="URIRef">http://www.knora.org/ontology/0068/nietzsche#pageBelongsToArchivalManuscriptUnity</pages> + <title type="URIRef">http://www.nie.org/ontology/nietzsche#hasTitle</title> + <manuscript_type type="URIRef">http://www.nie.org/ontology/nietzsche#hasManuscriptType</manuscript_type> + <pages type="URIRef">http://www.nie.org/ontology/nietzsche#hasPages</pages> </properties> </ArchivalManuscriptUnity> <Path> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#Path</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#Path</class_uri> <properties> - <d_attribute type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasDAttribute</d_attribute> - <style_class type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasStyleClass</style_class> + <d_attribute type="URIRef">http://www.nie.org/ontology/nietzsche#hasDAttribute</d_attribute> + <style_class type="URIRef">http://www.nie.org/ontology/nietzsche#hasStyleClass</style_class> </properties> </Path> <Box> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#Box</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#Box</class_uri> <properties> - <d_attribute type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasDAttribute</d_attribute> - <style_class type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasStyleClass</style_class> - <earlier_text type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasEarlierText</earlier_text> + <d_attribute type="URIRef">http://www.nie.org/ontology/nietzsche#hasDAttribute</d_attribute> + <style_class type="URIRef">http://www.nie.org/ontology/nietzsche#hasStyleClass</style_class> + <earlier_text type="URIRef">http://www.nie.org/ontology/nietzsche#hasEarlierText</earlier_text> </properties> </Box> <Image> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#Image</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#Image</class_uri> <properties> - <height type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasHeight</height> - <width type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasWidth</width> - <file_name type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasFileName</file_name> - <URL type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasUrl</URL> - <text_field type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTextField</text_field> + <height type="URIRef">http://www.nie.org/ontology/nietzsche#hasHeight</height> + <width type="URIRef">http://www.nie.org/ontology/nietzsche#hasWidth</width> + <file_name type="URIRef">http://www.nie.org/ontology/nietzsche#hasFileName</file_name> + <URL type="URIRef">http://www.nie.org/ontology/nietzsche#hasUrl</URL> </properties> </Image> <FaksimileImage> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#FaksimileImage</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#FaksimileImage</class_uri> <properties> - <height type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasHeight</height> - <width type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasWidth</width> - <file_name type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasFileName</file_name> - <URL type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasUrl</URL> - <text_field type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTextField</text_field> + <height type="URIRef">http://www.nie.org/ontology/nietzsche#hasHeight</height> + <width type="URIRef">http://www.nie.org/ontology/nietzsche#hasWidth</width> + <file_name type="URIRef">http://www.nie.org/ontology/nietzsche#hasFileName</file_name> + <URL type="URIRef">http://www.nie.org/ontology/nietzsche#hasUrl</URL> + <text_field type="URIRef">http://www.nie.org/ontology/nietzsche#hasTextField</text_field> </properties> </FaksimileImage> - <LineNumber> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#LineNumber</class_uri> + <PositionalObject> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#PositionalObject</class_uri> + <properties> + <height type="URIRef">http://www.nie.org/ontology/nietzsche#hasHeight</height> + <width type="URIRef">http://www.nie.org/ontology/nietzsche#hasWidth</width> + <left type="URIRef">http://www.nie.org/ontology/nietzsche#hasLeft</left> + <top type="URIRef">http://www.nie.org/ontology/nietzsche#hasTop</top> + <bottom type="URIRef">http://www.nie.org/ontology/nietzsche#hasBottom</bottom> + <transform type="URIRef">http://www.nie.org/ontology/nietzsche#hasTransform</transform> + </properties> + </PositionalObject> + <WordPosition> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#WordPosition</class_uri> <properties> - <id type="URIRef">http://www.knora.org/ontology/0068/nietzsche#lineHasNumber</id> - <bottom type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasBottom</bottom> - <top type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTop</top> + <height type="URIRef">http://www.nie.org/ontology/nietzsche#hasHeight</height> + <width type="URIRef">http://www.nie.org/ontology/nietzsche#hasWidth</width> + <left type="URIRef">http://www.nie.org/ontology/nietzsche#hasLeft</left> + <top type="URIRef">http://www.nie.org/ontology/nietzsche#hasTop</top> + <bottom type="URIRef">http://www.nie.org/ontology/nietzsche#hasBottom</bottom> + <transform type="URIRef">http://www.nie.org/ontology/nietzsche#hasTransform</transform> </properties> - </LineNumber> + </WordPosition> + <FaksimilePosition> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#FaksimilePosition</class_uri> + <properties> + <height type="URIRef">http://www.nie.org/ontology/nietzsche#hasHeight</height> + <width type="URIRef">http://www.nie.org/ontology/nietzsche#hasWidth</width> + <left type="URIRef">http://www.nie.org/ontology/nietzsche#hasLeft</left> + <top type="URIRef">http://www.nie.org/ontology/nietzsche#hasTop</top> + <bottom type="URIRef">http://www.nie.org/ontology/nietzsche#hasBottom</bottom> + <transform type="URIRef">http://www.nie.org/ontology/nietzsche#hasTransform</transform> + <faksimile_image type="URIRef">http://www.nie.org/ontology/nietzsche#isOnFaksimileImage</faksimile_image> + <text_field type="URIRef">http://www.nie.org/ontology/nietzsche#isOnTextField</text_field> + </properties> + </FaksimilePosition> + <Line> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#Line</class_uri> + <properties> + <id type="URIRef">http://www.nie.org/ontology/nietzsche#lineHasNumber</id> + <bottom type="URIRef">http://www.nie.org/ontology/nietzsche#hasBottom</bottom> + <top type="URIRef">http://www.nie.org/ontology/nietzsche#hasTop</top> + <is_even type="URIRef">http://www.nie.org/ontology/nietzsche#isMainLine</is_even> + </properties> + </Line> <SimpleWord> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#SimpleWord</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#SimpleWord</class_uri> <properties> - <text type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasText</text> - <line_number type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordHasLineNumber</line_number> - <faksimile_positions type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordPositionBelongsToSimpleWord</faksimile_positions> - <transkription_positions type="URIRef">http://www.knora.org/ontology/0068/nietzsche#transkriptionPositionBelongsToSimpleWord</transkription_positions> + <transkription_positions type="URIRef">http://www.nie.org/ontology/nietzsche#hasTranskriptionPositions</transkription_positions> + <faksimile_positions type="URIRef">http://www.nie.org/ontology/nietzsche#hasFaksimilePositions</faksimile_positions> + <text type="URIRef">http://www.nie.org/ontology/nietzsche#hasText</text> + <lines type="URIRef">http://www.nie.org/ontology/nietzsche#wordBelongsToLine</lines> </properties> </SimpleWord> <SpecialWord> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#SpecialWord</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#SpecialWord</class_uri> <properties> - <text type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasText</text> - <line_number type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordHasLineNumber</line_number> - <faksimile_positions type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordPositionBelongsToSimpleWord</faksimile_positions> - <transkription_positions type="URIRef">http://www.knora.org/ontology/0068/nietzsche#transkriptionPositionBelongsToSimpleWord</transkription_positions> + <transkription_positions type="URIRef">http://www.nie.org/ontology/nietzsche#hasTranskriptionPositions</transkription_positions> + <faksimile_positions type="URIRef">http://www.nie.org/ontology/nietzsche#hasFaksimilePositions</faksimile_positions> + <text type="URIRef">http://www.nie.org/ontology/nietzsche#hasText</text> + <lines type="URIRef">http://www.nie.org/ontology/nietzsche#wordBelongsToLine</lines> </properties> </SpecialWord> <MarkForeignHands> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#MarkForeignHands</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#MarkForeignHands</class_uri> <properties> - <text type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasText</text> - <foreign_hands_text type="URIRef">http://www.knora.org/ontology/0068/nietzsche#textOfForeignHands</foreign_hands_text> - <pen type="URIRef">http://www.knora.org/ontology/0068/nietzsche#penOfForeignHands</pen> - <line_number type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordHasLineNumber</line_number> - <faksimile_positions type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordPositionBelongsToSimpleWord</faksimile_positions> - <transkription_positions type="URIRef">http://www.knora.org/ontology/0068/nietzsche#transkriptionPositionBelongsToSimpleWord</transkription_positions> + <transkription_positions type="URIRef">http://www.nie.org/ontology/nietzsche#hasTranskriptionPositions</transkription_positions> + <faksimile_positions type="URIRef">http://www.nie.org/ontology/nietzsche#hasFaksimilePositions</faksimile_positions> + <text type="URIRef">http://www.nie.org/ontology/nietzsche#hasText</text> + <foreign_hands_text type="URIRef">http://www.nie.org/ontology/nietzsche#textOfForeignHands</foreign_hands_text> + <pen type="URIRef">http://www.nie.org/ontology/nietzsche#penOfForeignHands</pen> + <lines type="URIRef">http://www.nie.org/ontology/nietzsche#wordBelongsToLine</lines> </properties> </MarkForeignHands> <Page> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#Page</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#Page</class_uri> <properties> - <number type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasNumber</number> - <orientation type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasOrientation</orientation> - <faksimile_image type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasFaksimileImage</faksimile_image> - <line_numbers type="URIRef">http://www.knora.org/ontology/0068/nietzsche#lineNumberBelongsToPage</line_numbers> - <words type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordBelongsToPage</words> - <svg_image type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasSvgImage</svg_image> - <writing_processes type="URIRef">http://www.knora.org/ontology/0068/nietzsche#writingProcessBelongsToPage</writing_processes> - <word_deletion_paths type="URIRef">http://www.knora.org/ontology/0068/nietzsche#pathBelongsToPage</word_deletion_paths> - <word_insertion_marks type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordInsertionMarkBelongsToPage</word_insertion_marks> + <number type="URIRef">http://www.nie.org/ontology/nietzsche#hasNumber</number> + <orientation type="URIRef">http://www.nie.org/ontology/nietzsche#hasOrientation</orientation> + <lines type="URIRef">http://www.nie.org/ontology/nietzsche#hasLines</lines> + <words type="URIRef">http://www.nie.org/ontology/nietzsche#hasWords</words> + <writing_processes type="URIRef">http://www.nie.org/ontology/nietzsche#hasWritingProcesses</writing_processes> + <word_deletion_paths type="URIRef">http://www.nie.org/ontology/nietzsche#hasWordDeletionPaths</word_deletion_paths> + <word_insertion_marks type="URIRef">http://www.nie.org/ontology/nietzsche#hasWordInsertionMarks</word_insertion_marks> + <faksimile_image type="URIRef">http://www.nie.org/ontology/nietzsche#hasFaksimileImage</faksimile_image> + <svg_image type="URIRef">http://www.nie.org/ontology/nietzsche#hasSvgImage</svg_image> + <text_field type="URIRef">http://www.nie.org/ontology/nietzsche#pageIsOnTextField</text_field> </properties> </Page> - <PositionalObject> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#PositionalObject</class_uri> - <properties> - <height type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasHeight</height> - <width type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasWidth</width> - <left type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasLeft</left> - <top type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTop</top> - <bottom type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasBottom</bottom> - <transform type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTransform</transform> - </properties> - </PositionalObject> - <PositionalWordPart> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#PositionalWordPart</class_uri> - <properties> - <height type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasHeight</height> - <width type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasWidth</width> - <left type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasLeft</left> - <top type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTop</top> - <bottom type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasBottom</bottom> - <transform type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTransform</transform> - <text type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasText</text> - <symbol_id type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasSymbolId</symbol_id> - <style_class type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasStyleClass</style_class> - </properties> - </PositionalWordPart> <Reference> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#Reference</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#Reference</class_uri> <properties> - <first_line type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasFirstLine</first_line> - <last_line type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasLastLine</last_line> - <is_uncertain type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasIsUncertain</is_uncertain> - <title type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTitle</title> - <page_number type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasPageNumber</page_number> + <first_line type="URIRef">http://www.nie.org/ontology/nietzsche#firstLineOfReference</first_line> + <last_line type="URIRef">http://www.nie.org/ontology/nietzsche#lastLineOfReference</last_line> + <is_uncertain type="URIRef">http://www.nie.org/ontology/nietzsche#IsUncertain</is_uncertain> + <title type="URIRef">http://www.nie.org/ontology/nietzsche#hasTitle</title> + <page_number type="URIRef">http://www.nie.org/ontology/nietzsche#hasPageNumber</page_number> </properties> </Reference> <SVGImage> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#SVGImage</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#SVGImage</class_uri> <properties> - <height type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasHeight</height> - <width type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasWidth</width> - <file_name type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasFileName</file_name> - <URL type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasUrl</URL> - <text_field type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTextField</text_field> + <height type="URIRef">http://www.nie.org/ontology/nietzsche#hasHeight</height> + <width type="URIRef">http://www.nie.org/ontology/nietzsche#hasWidth</width> + <file_name type="URIRef">http://www.nie.org/ontology/nietzsche#hasFileName</file_name> + <URL type="URIRef">http://www.nie.org/ontology/nietzsche#hasUrl</URL> </properties> </SVGImage> <TextConnectionMark> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#TextConnectionMark</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#TextConnectionMark</class_uri> <properties> - <text type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasText</text> - <line_number type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordHasLineNumber</line_number> - <faksimile_positions type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordPositionBelongsToSimpleWord</faksimile_positions> - <transkription_positions type="URIRef">http://www.knora.org/ontology/0068/nietzsche#transkriptionPositionBelongsToSimpleWord</transkription_positions> + <transkription_positions type="URIRef">http://www.nie.org/ontology/nietzsche#hasTranskriptionPositions</transkription_positions> + <faksimile_positions type="URIRef">http://www.nie.org/ontology/nietzsche#hasFaksimilePositions</faksimile_positions> + <text type="URIRef">http://www.nie.org/ontology/nietzsche#hasText</text> + <lines type="URIRef">http://www.nie.org/ontology/nietzsche#wordBelongsToLine</lines> + <text_source type="URIRef">http://www.nie.org/ontology/nietzsche#textConnectionMarkHasTextSource</text_source> </properties> </TextConnectionMark> <TextField> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#TextField</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#TextField</class_uri> <properties> - <height type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasHeight</height> - <width type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasWidth</width> - <left type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasLeft</left> - <top type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTop</top> - <bottom type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasBottom</bottom> - <transform type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTransform</transform> + <height type="URIRef">http://www.nie.org/ontology/nietzsche#hasHeight</height> + <width type="URIRef">http://www.nie.org/ontology/nietzsche#hasWidth</width> + <left type="URIRef">http://www.nie.org/ontology/nietzsche#hasLeft</left> + <top type="URIRef">http://www.nie.org/ontology/nietzsche#hasTop</top> + <bottom type="URIRef">http://www.nie.org/ontology/nietzsche#hasBottom</bottom> + <transform type="URIRef">http://www.nie.org/ontology/nietzsche#hasTransform</transform> </properties> </TextField> - <WordPosition> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#WordPosition</class_uri> - <properties> - <height type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasHeight</height> - <width type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasWidth</width> - <left type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasLeft</left> - <top type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTop</top> - <bottom type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasBottom</bottom> - <transform type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTransform</transform> - </properties> - </WordPosition> <TranskriptionPosition> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#TranskriptionPosition</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#TranskriptionPosition</class_uri> <properties> - <height type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasHeight</height> - <width type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasWidth</width> - <left type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasLeft</left> - <top type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTop</top> - <bottom type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasBottom</bottom> - <transform type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTransform</transform> - <positional_word_parts type="URIRef">http://www.knora.org/ontology/0068/nietzsche#positionalWordPartBelongsToTranskriptionPosition</positional_word_parts> + <height type="URIRef">http://www.nie.org/ontology/nietzsche#hasHeight</height> + <width type="URIRef">http://www.nie.org/ontology/nietzsche#hasWidth</width> + <left type="URIRef">http://www.nie.org/ontology/nietzsche#hasLeft</left> + <top type="URIRef">http://www.nie.org/ontology/nietzsche#hasTop</top> + <bottom type="URIRef">http://www.nie.org/ontology/nietzsche#hasBottom</bottom> + <transform type="URIRef">http://www.nie.org/ontology/nietzsche#hasTransform</transform> + <svg_image type="URIRef">http://www.nie.org/ontology/nietzsche#isOnSvgImage</svg_image> </properties> </TranskriptionPosition> - <WordPart> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#WordPart</class_uri> - <properties> - <has_seqnum type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordHasSeqNum</has_seqnum> - <has_part type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordPartHasWord</has_part> - </properties> - </WordPart> <Word> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#Word</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#Word</class_uri> <properties> - <text type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasText</text> - <deleted type="URIRef">http://www.knora.org/ontology/0068/nietzsche#isWordDeleted</deleted> - <line_number type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordHasLineNumber</line_number> - <faksimile_positions type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordPositionBelongsToSimpleWord</faksimile_positions> - <transkription_positions type="URIRef">http://www.knora.org/ontology/0068/nietzsche#transkriptionPositionBelongsToSimpleWord</transkription_positions> - <writing_process_id type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordBelongsToWritingProcess</writing_process_id> - <word_parts type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordHasWordPart</word_parts> + <transkription_positions type="URIRef">http://www.nie.org/ontology/nietzsche#hasTranskriptionPositions</transkription_positions> + <faksimile_positions type="URIRef">http://www.nie.org/ontology/nietzsche#hasFaksimilePositions</faksimile_positions> + <text type="URIRef">http://www.nie.org/ontology/nietzsche#hasText</text> + <deleted type="URIRef">http://www.nie.org/ontology/nietzsche#isWordDeleted</deleted> + <word_parts type="URIRef">http://www.nie.org/ontology/nietzsche#wordHasWordParts</word_parts> + <lines type="URIRef">http://www.nie.org/ontology/nietzsche#wordBelongsToLine</lines> + <writing_processes type="URIRef">http://www.nie.org/ontology/nietzsche#wordBelongsToWritingProcess</writing_processes> </properties> </Word> <WordInsertionMark> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#WordInsertionMark</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#WordInsertionMark</class_uri> <properties> - <height type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasHeight</height> - <width type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasWidth</width> - <left type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasLeft</left> - <top type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTop</top> - <bottom type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasBottom</bottom> - <transform type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasTransform</transform> - <mark_type type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasMarkType</mark_type> - <symbol_id type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasSymbolId</symbol_id> - <next_word_id type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasNextWord</next_word_id> - <previous_word_id type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasPreviousWord</previous_word_id> - <line_number type="URIRef">http://www.knora.org/ontology/0068/nietzsche#wordInsertionMarkHasLineNumber</line_number> + <height type="URIRef">http://www.nie.org/ontology/nietzsche#hasHeight</height> + <width type="URIRef">http://www.nie.org/ontology/nietzsche#hasWidth</width> + <left type="URIRef">http://www.nie.org/ontology/nietzsche#hasLeft</left> + <top type="URIRef">http://www.nie.org/ontology/nietzsche#hasTop</top> + <bottom type="URIRef">http://www.nie.org/ontology/nietzsche#hasBottom</bottom> + <transform type="URIRef">http://www.nie.org/ontology/nietzsche#hasTransform</transform> + <mark_type type="URIRef">http://www.nie.org/ontology/nietzsche#hasMarkType</mark_type> + <symbol_id type="URIRef">http://www.nie.org/ontology/nietzsche#hasSymbolId</symbol_id> + <next_word_id type="URIRef">http://www.nie.org/ontology/nietzsche#hasNextWord</next_word_id> + <previous_word_id type="URIRef">http://www.nie.org/ontology/nietzsche#hasPreviousWord</previous_word_id> + <line type="URIRef">http://www.nie.org/ontology/nietzsche#wordInsertionMarkBelongsToLine</line> </properties> </WordInsertionMark> <WritingProcess> - <class_uri type="URIRef">http://www.knora.org/ontology/0068/nietzsche#WritingProcess</class_uri> + <class_uri type="URIRef">http://www.nie.org/ontology/nietzsche#WritingProcess</class_uri> <properties> - <version type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasVersion</version> - <description type="URIRef">http://www.knora.org/ontology/0068/nietzsche#hasDescription</description> + <version type="URIRef">http://www.nie.org/ontology/nietzsche#hasVersion</version> + <description type="URIRef">http://www.nie.org/ontology/nietzsche#hasDescription</description> </properties> </WritingProcess> </classes> </dict> <metadata> <type>xml-dictionary</type> <createdBy> <script>dict2xml</script> - <date>2019-10-16 17:41:18</date> + <date>2019-11-08 10:30:59</date> </createdBy> </metadata> </root> Index: svgscripts/datatypes/lineNumber.py =================================================================== --- svgscripts/datatypes/lineNumber.py (revision 68) +++ svgscripts/datatypes/lineNumber.py (revision 69) @@ -1,104 +1,103 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ This class can be used to represent a line number. """ # Copyright (C) University of Basel 2019 {{{1 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/> 1}}} __author__ = "Christian Steiner" __maintainer__ = __author__ __copyright__ = 'University of Basel' __email__ = "christian.steiner@unibas.ch" __status__ = "Development" __license__ = "GPL v3" __version__ = "0.0.1" import re from lxml import etree as ET from os.path import isfile import sys from .matrix import Matrix sys.path.append('py2ttl') -from class_spec import SemanticClass -class LineNumber(SemanticClass): +class LineNumber: """ This class represents a line number. Args: file_name (str): name of the xml file to be instantiated. """ XML_TAG = 'line-number' WARN_NO_LINE_NUMBER = 'No line number found' def __init__(self, id=0, bottom=0.0, top=0.0, raw_text_node=None, transkription_field=None, xml_text_node=None): self.id = id self.bottom = bottom self.top = top if xml_text_node is not None: self.id = int(xml_text_node.get('id')) self.bottom = float(xml_text_node.get('bottom')) self.top = float(xml_text_node.get('top')) if raw_text_node is not None and transkription_field is not None: matrix = Matrix(raw_text_node.get('transform'), transkription_field=transkription_field) self.bottom = matrix.getY() self.id = int(raw_text_node.text) if raw_text_node.text is not None\ else int(''.join([x.text for x in raw_text_node.findall('.//tspan', raw_text_node.nsmap)])) @classmethod def get_semantic_dictionary(cls): """ Creates and returns a semantic dictionary as specified by SemanticClass. """ dictionary = {} class_dict = cls.get_class_dictionary() properties = {\ 'id': { 'class': int, 'cardinality': 1,\ 'name': 'lineHasNumber', 'label': 'line has number',\ 'comment': 'Relating a line to a number it has.'},\ } properties.update(cls.create_semantic_property_dictionary('bottom', float, 1)) properties.update(cls.create_semantic_property_dictionary('top', float, 1)) dictionary.update({'class': class_dict}) dictionary.update({'properties': properties}) return dictionary @staticmethod def IS_A_LINE_NUMBER(raw_text_node): """Returns whether svg node contains a line number. """ if raw_text_node.text is not None: return bool(re.search(r'^[0-9]+$', raw_text_node.text)) elif len(raw_text_node.findall('.//tspan', raw_text_node.nsmap)) > 0: text = ''.join([x.text for x in raw_text_node.findall('.//tspan', raw_text_node.nsmap)]) return bool(re.search(r'^[0-9]+$', text)) return False def setTop(self, top): """Sets top position of line number. """ self.top = top def attach_object_to_tree(self, target_tree): """Attach object to tree. """ obj_node = target_tree.getroot().xpath('//' + LineNumber.XML_TAG + '[@id="%s"]' % self.id)[0] \ if(len(target_tree.getroot().xpath('//' + LineNumber.XML_TAG + '[@id="%s"]' % self.id)) > 0) \ else ET.SubElement(target_tree.getroot(), LineNumber.XML_TAG) for key in self.__dict__.keys(): obj_node.set(key.replace('_','-'), str(round(self.__dict__[key], 3))) Index: svgscripts/datatypes/faksimile_image.py =================================================================== --- svgscripts/datatypes/faksimile_image.py (revision 68) +++ svgscripts/datatypes/faksimile_image.py (revision 69) @@ -1,103 +1,102 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ This class can be used to represent faksimile images. """ # Copyright (C) University of Basel 2019 {{{1 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/> 1}}} __author__ = "Christian Steiner" __maintainer__ = __author__ __copyright__ = 'University of Basel' __email__ = "christian.steiner@unibas.ch" __status__ = "Development" __license__ = "GPL v3" __version__ = "0.0.1" import fnmatch from lxml import etree as ET import os from os.path import basename, dirname, isfile, realpath, sep import sys from .image import Image from .text_field import TextField sys.path.append('svgscripts') from local_config import FAKSIMILE_LOCATION class FaksimileImage(Image): """ This class represents a faksimile image. Args: file_name (str): name of the image file. node (lxml.etree.Element) node, containing information URL (str): URL of image file. height (float): height of image width (float): width of image x (float): x y (float): y """ XML_TAG = 'faksimile-image' NIETZSCHE_SOURCES_URL = 'http://www.nietzschesource.org/DFGAapi/api/page/download/' def __init__(self, node=None, file_name=None, local_path=None, URL=None, height=0.0, width=0.0, x=0.0, y=0.0, text_field=None): super(FaksimileImage, self).__init__(node=node, file_name=file_name, URL=URL, local_path=local_path,\ height=height, width=width, text_field=text_field, tag=self.XML_TAG) self.x = x self.y = y def get_image_joined_with_text_field(self, text_field): """Returns a new instance of itself that has a text_field (text_field.TextField). """ return FaksimileImage(file_name=self.file_name, local_path=self.local_path, URL=self.URL, height=self.height,\ width=self.width, x=self.x, y=self.y, text_field=text_field) @classmethod def get_semantic_dictionary(cls): """ Creates and returns a semantic dictionary as specified by SemanticClass. """ dictionary = super(FaksimileImage,cls).get_semantic_dictionary() - dictionary['properties'].update(cls.create_semantic_property_dictionary('text_field', TextField, cardinality=1,\ - cardinality_restriction='minCardinality')) + dictionary['properties'].update(cls.create_semantic_property_dictionary('text_field', TextField)) return dictionary @staticmethod def CREATE_IMAGE(image_node, source_file=None): """Instantiates a FaksimileImage from a (lxml.etree.Element) image_node. """ namespaces = image_node.nsmap if len(namespaces) == 0: namespaces = { 'xlink': '' } local_path = image_node.get('{%s}href' % namespaces['xlink']) file_name = basename(local_path) if file_name != local_path and source_file is not None: local_path = realpath(dirname(source_file)) + sep + local_path local_path = realpath(local_path) if not isfile(local_path): local_path = None for path, dirs, files in os.walk(os.path.abspath(FAKSIMILE_LOCATION)): for filename in fnmatch.filter(files, file_name): local_path = os.path.join(path, filename) break URL = FaksimileImage.NIETZSCHE_SOURCES_URL + file_name.replace('.jpg','') height = float(image_node.get('height')) if bool(image_node.get('height')) else 0.0 width = float(image_node.get('width')) if bool(image_node.get('width')) else 0.0 x = float(image_node.get('x')) if bool(image_node.get('x')) else 0.0 y = float(image_node.get('y')) if bool(image_node.get('y')) else 0.0 return FaksimileImage(file_name=file_name, local_path=local_path, URL=URL, height=height, width=width, x=x, y=y) Index: svgscripts/datatypes/word.py =================================================================== --- svgscripts/datatypes/word.py (revision 68) +++ svgscripts/datatypes/word.py (revision 69) @@ -1,495 +1,509 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ This class can be used to represent a word. """ # Copyright (C) University of Basel 2019 {{{1 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/> 1}}} __author__ = "Christian Steiner" __maintainer__ = __author__ __copyright__ = 'University of Basel' __email__ = "christian.steiner@unibas.ch" __status__ = "Development" __license__ = "GPL v3" __version__ = "0.0.1" from lxml import etree as ET from operator import attrgetter import sys import warnings -from .lineNumber import LineNumber from .matrix import Matrix from .path import Path from .simple_word import SimpleWord from .word_position import WordPosition from .transkription_position import TranskriptionPosition from .writing_process import WritingProcess sys.path.append('py2ttl') from class_spec import SemanticClass class Word(SimpleWord): """ This class represents a word. """ DATA = 'debug-data' XML_TAG = 'word' XML_EARLIER_VERSION = 'earlier-version' def __init__(self, id=0, text='', line_number=-1, deleted=False, transkription_positions=None, faksimile_positions=None, word_part_objs=None, word_parts=None, writing_process_id=-1, earlier_version=None, box_paths=None): super(Word,self).__init__(id=id, text=text, line_number=line_number, transkription_positions=transkription_positions,\ faksimile_positions=faksimile_positions) self.deleted = deleted self.debug_container = {} if len([ tp.get_text() for tp in self.transkription_positions if type(tp) == TranskriptionPosition ]) > len(self.text): self.text = ''.join([ tp.get_text() for tp in self.transkription_positions ]) self.word_part_objs = word_part_objs if word_part_objs is not None else [] self.is_head_of_inserted_words = False self.is_tail_of_inserted_words = False self.is_before_inserted_words = False self.is_after_inserted_words = False self.word_insertion_mark = None self.debug_msg = None self.writing_process_id = writing_process_id + self.writing_processes = [] self.word_parts = word_parts if word_parts is not None else [] self.earlier_version = earlier_version self.box_paths = box_paths if box_paths is not None else [] def attach_word_to_tree(self, target_tree): """Attaches word to tree target_tree. """ word_node = super(Word,self).attach_word_to_tree(target_tree) if self.deleted is not None: word_node.set('deleted', str(self.deleted).lower()) if self.writing_process_id > -1: word_node.set('writing-process-id', str(self.writing_process_id)) for word_part in self.word_parts: word_part.attach_word_to_tree(word_node) if self.earlier_version is not None: earlier_node = ET.SubElement(word_node, self.XML_EARLIER_VERSION) self.earlier_version.attach_word_to_tree(earlier_node) for index, box_path in enumerate(self.box_paths): box_path.id = index box_path.attach_object_to_tree(word_node) return word_node def belongs_to_multiple_writing_processes(self, include_parts=False): """Returns true if transkription_positions belong to different WritingProcesses. """ if len(self.word_parts) > 0 and include_parts: return len(set(word.writing_process_id for word in self.word_parts)) > 1 return len(set(tp.writing_process_id for tp in self.transkription_positions )) > 1 def get_partial_word_over_box(self): """Partition a word according to its transkription_positions' has_box ->split word and add partial words as its parts. :return: word over box or self """ word_over_box = self if self.has_mixed_status('has_box'): transkription_positions = [] last_status = None for transkription_position in self.transkription_positions: if transkription_position.has_box != last_status\ and len(transkription_positions) > 0: newWord = Word(id=len(self.word_parts), line_number=self.line_number,\ transkription_positions=transkription_positions, deleted=self.deleted, writing_process_id=self.writing_process_id) self.word_parts.append(newWord) if last_status: word_over_box = newWord transkription_positions = [] transkription_positions.append(transkription_position) last_status = transkription_position.has_box if len(transkription_positions) > 0: newWord = Word(id=len(self.word_parts), line_number=self.line_number,\ transkription_positions=transkription_positions, deleted=self.deleted, writing_process_id=self.writing_process_id) self.word_parts.append(newWord) if last_status: word_over_box = newWord self.transkription_positions = [] self.line_number = -1 elif len(self.word_parts) > 0: self.word_parts, word_over_box = execute_function_on_parts(self.word_parts, 'get_partial_word_over_box') return word_over_box def has_mixed_status(self, property_key, include_parts=False): """Returns true if transkription_positions belong to different WritingProcesses. """ if False in set(property_key in tp.__dict__.keys() for tp in self.transkription_positions): return False if len(self.word_parts) > 0 and include_parts: if False in set(property_key in word.__dict__.keys() for word in self.word_parts): return False return len(set(word.deleted for word in self.word_parts)) > 1 return len(set(tp.__dict__[property_key] for tp in self.transkription_positions )) > 1 + def init_word(self, page): + """Initialize word with objects from page. + """ + super(Word,self).init_word(page) + if self.writing_process_id > -1: + self.writing_processes += [ wp for wp in page.writing_processes if wp.id == self.writing_process_id ] + writing_processes = self.writing_processes + for word_part in self.word_parts: + word_part.init_word(page) + self.lines += word_part.lines + self.writing_processes + word_part.writing_processes + self.lines = [ line for line in set(self.lines) ] + self.writing_processes = [ wp for wp in set(self.writing_processes)] + def partition_according_to_deletion(self): """Partition a word according to its transkription_positions' deletion status ->split word and add partial words as its parts. """ if self.has_mixed_status('deleted'): transkription_positions = [] last_status = None for transkription_position in self.transkription_positions: if transkription_position.deleted != last_status\ and len(transkription_positions) > 0: newWord = Word(id=len(self.word_parts), line_number=self.line_number,\ transkription_positions=transkription_positions, deleted=last_status, writing_process_id=self.writing_process_id) self.word_parts.append(newWord) transkription_positions = [] transkription_positions.append(transkription_position) last_status = transkription_position.deleted if len(transkription_positions) > 0: newWord = Word(id=len(self.word_parts), line_number=self.line_number,\ transkription_positions=transkription_positions, deleted=last_status, writing_process_id=self.writing_process_id) self.word_parts.append(newWord) self.transkription_positions = [] self.line_number = -1 self.deleted = False elif len(self.word_parts) > 0: self.word_parts, none = execute_function_on_parts(self.word_parts, 'partition_according_to_deletion') elif not self.deleted\ and len(self.transkription_positions) > 0\ and self.transkription_positions[0].deleted: self.deleted = True def partition_according_to_writing_process_id(self): """Partition a word according to its transkription_positions' writing_process_ids ->split word and add partial words as its parts. """ if self.belongs_to_multiple_writing_processes(): last_writing_process_id = -1 transkription_positions = [] for transkription_position in self.transkription_positions: if transkription_position.writing_process_id != last_writing_process_id\ and len(transkription_positions) > 0: newWord = Word(id=len(self.word_parts), line_number=self.line_number,\ transkription_positions=transkription_positions, writing_process_id=last_writing_process_id) self.word_parts.append(newWord) transkription_positions = [] transkription_positions.append(transkription_position) last_writing_process_id = transkription_position.writing_process_id if len(transkription_positions) > 0: newWord = Word(id=len(self.word_parts), line_number=self.line_number,\ transkription_positions=transkription_positions, writing_process_id=last_writing_process_id) self.word_parts.append(newWord) self.transkription_positions = [] self.line_number = -1 elif len(self.word_parts) > 0: self.word_parts, none = execute_function_on_parts(self.word_parts, 'partition_according_to_writing_process_id') if self.belongs_to_multiple_writing_processes(include_parts=True): self.writing_process_id = sorted(set([ word.writing_process_id for word in self.word_parts ]), reverse=True)[0] elif len(self.transkription_positions) > 0: self.writing_process_id = self.transkription_positions[0].writing_process_id def process_boxes(self, box_paths, parent_word=None, tr_xmin=0.0, tr_ymin=0.0): """Determines whether word is over a word box. """ test_case = len(box_paths) == 1 later_version_word = None if len(self.word_parts) > 0: for word in self.word_parts: later_version = word.process_boxes(box_paths, parent_word=self, tr_xmin=tr_xmin, tr_ymin=tr_ymin) if later_version is not None and later_version.earlier_version is not None: later_version_word = later_version else: new_tp_dict = {} for transkription_position in self.transkription_positions: word_path = Path.create_path_from_transkription_position(transkription_position,\ tr_xmin=tr_xmin, tr_ymin=tr_ymin) containing_boxes = [ box_path for box_path in box_paths\ if word_path.is_partially_contained_by(box_path)\ or box_path.do_paths_intersect(word_path) ] if len(containing_boxes) > 0: box_path = containing_boxes[0] if box_path.contains_path(word_path): transkription_position.has_box = box_path elif box_path.contains_start_of_path(word_path): split_position = box_path.path.bbox()[1] - tr_xmin new_tps = transkription_position.split(split_position) if len(new_tps) == 2: new_tps[0].has_box = box_path new_tp_dict.update({ transkription_position: new_tps }) else: transkription_position.has_box = box_path elif box_path.contains_end_of_path(word_path): split_position = box_path.path.bbox()[0] - tr_xmin new_tps = transkription_position.split(split_position) if len(new_tps) == 2: new_tps[1].has_box = box_path new_tp_dict.update({ transkription_position: new_tps }) else: transkription_position.has_box = box_path else: split_position1 = box_path.path.bbox()[0] - tr_xmin split_position2 = box_path.path.bbox()[1] - tr_xmin new_tps = transkription_position.split(split_position1, split_position2) if len(new_tps) >= 2: new_tps[1].has_box = box_path new_tp_dict.update({ transkription_position: new_tps }) else: transkription_position.has_box = box_path for replace_tp in new_tp_dict.keys(): for tp in new_tp_dict.get(replace_tp): self.transkription_positions.insert(self.transkription_positions.index(replace_tp), tp) self.transkription_positions.remove(replace_tp) update_transkription_position_ids(self) later_version_word = self.get_partial_word_over_box() if len(later_version_word.transkription_positions) > 0\ and later_version_word.transkription_positions[0].has_box is not None: box_holder = self if parent_word is None else parent_word box_holder.box_paths.append(later_version_word.transkription_positions[0].has_box) box_text = later_version_word.transkription_positions[0].has_box.earlier_text transkription_positions = TranskriptionPosition.copy_list_of_cls(later_version_word.transkription_positions) later_version_word.earlier_version = Word(text=box_text, transkription_positions=transkription_positions) #print(later_version_word.text, later_version_word.earlier_version.text) return later_version_word return later_version_word def split(self, split_string, start_id=0): """Splits the word and returns an 3-tuple of new words. """ previousString, currentString, nextString = self.text.partition(split_string) currentWord = None previousWord = None nextWord = None previousIndex = 0 current_id = start_id all_positional_word_parts = [] for position in self.transkription_positions: all_positional_word_parts += position.positional_word_parts if len(all_positional_word_parts) == 0: warnings.warn('ATTENTION: Word: {} {} with Strings "{}, {}, {}": there are no parts!'.format(self.id, self.text, previousString, currentString, nextString)) if len(previousString) > 0: previous_pwps = [] while previousIndex < len(all_positional_word_parts) and previousString != ''.join([ pwp.text for pwp in previous_pwps ]): previous_pwps.append(all_positional_word_parts[previousIndex]) previousIndex += 1 if previousString != ''.join([ pwp.text for pwp in previous_pwps ]): warnings.warn('ATTENTION: "{}" does not match a word_part_obj!'.format(previousString)) else: previous_transkription_positions = TranskriptionPosition.CREATE_TRANSKRIPTION_POSITION_LIST_FROM_PWPS(previous_pwps, debug_msg_string='word.split') previous_text = ''.join([ pwp.text for pwp in previous_pwps ]) previousWord = Word(text=previous_text, id=current_id, line_number=self.line_number, transkription_positions=previous_transkription_positions) current_id += 1 all_positional_word_parts = all_positional_word_parts[previousIndex:] if len(nextString) > 0: tmp_pwps = [] index = 0 while index < len(all_positional_word_parts) and currentString != ''.join([ pwp.text for pwp in tmp_pwps ]): tmp_pwps.append(all_positional_word_parts[index]) index += 1 if currentString != ''.join([ pwp.text for pwp in tmp_pwps ]): warnings.warn('ATTENTION: "{}" does not match a word_part_obj!'.format(currentString)) else: next_pwps = all_positional_word_parts[index:] next_transkription_positions = TranskriptionPosition.CREATE_TRANSKRIPTION_POSITION_LIST_FROM_PWPS(next_pwps, debug_msg_string='word.split') next_text = ''.join([ pwp.text for pwp in next_pwps ]) nextWord = Word(text=next_text, id=current_id+1, line_number=self.line_number, transkription_positions=next_transkription_positions) all_positional_word_parts = all_positional_word_parts[:index] current_transkription_positions = TranskriptionPosition.CREATE_TRANSKRIPTION_POSITION_LIST_FROM_PWPS(all_positional_word_parts, debug_msg_string='word.split') current_text = ''.join([ pwp.text for pwp in all_positional_word_parts ]) currentWord = Word(text=current_text, id=current_id, line_number=self.line_number, transkription_positions=current_transkription_positions) return previousWord, currentWord, nextWord def split_according_to_status(self, status): """Split a word according to its transkription_positions' text. :return: a list of new word.Word """ new_words = [] if self.has_mixed_status(status): last_status = None transkription_positions = [] copy_keys = [ 'line_number', 'text', 'deleted', 'writing_process_id' ] for transkription_position in self.transkription_positions: if transkription_position.__dict__[status] != last_status\ and len(transkription_positions) > 0: newWord = Word(id=self.id+len(new_words), transkription_positions=transkription_positions) for key in copy_keys: if key != status and key in self.__dict__.keys(): newWord.__dict__[key] = self.__dict__[key] newWord.__dict__[status] = transkription_positions[0].__dict__[status] new_words.append(newWord) transkription_positions = [] transkription_positions.append(transkription_position) last_status = transkription_position.__dict__[status] if len(transkription_positions) > 0: newWord = Word(id=self.id+len(new_words), transkription_positions=transkription_positions) for key in copy_keys: if key != status and key in self.__dict__.keys(): newWord.__dict__[key] = self.__dict__[key] newWord.__dict__[status] = transkription_positions[0].__dict__[status] new_words.append(newWord) return new_words def join(self, other_word, append_at_end_of_new_word=True): """Joins other_word with this word by changing the text of current word and adding other_word.transkription_positions. """ if append_at_end_of_new_word: self.text = self.text + other_word.text for position in other_word.transkription_positions: position.id = str(len(self.transkription_positions)) self.transkription_positions.append(position) else: self.text = other_word.text + self.text index = 0 for position in other_word.transkription_positions: self.transkription_positions.insert(index, position) index += 1 while index < len(self.transkription_positions): self.transkription_positions[index].id = str(index) index += 1 self.simplify_transkription_positions() def set_word_insertion_mark(self, word_insertion_mark): """Sets word_insertion_mark """ self.word_insertion_mark = word_insertion_mark def simplify_transkription_positions(self): """Merge transkription_positions if possible. """ index = len(self.transkription_positions)-1 while index > 0\ and False not in [ 'positional_word_parts' in tp.__dict__.keys() for tp in self.transkription_positions ]: current_tp = self.transkription_positions[index] index -= 1 previous_tp = self.transkription_positions[index] if previous_tp.writing_process_id == current_tp.writing_process_id: positional_word_parts = previous_tp.positional_word_parts positional_word_parts += current_tp.positional_word_parts transkription_positions = TranskriptionPosition.CREATE_TRANSKRIPTION_POSITION_LIST_FROM_PWPS(\ positional_word_parts, debug_msg_string='simplifying transkription positions', transkription_position_id=previous_tp.id) if len(transkription_positions) == 1: transkription_positions[0].writing_process_id = previous_tp.writing_process_id self.transkription_positions.pop(index+1) self.transkription_positions[index] = transkription_positions[0] #print(self.text, len(self.transkription_positions)) @classmethod def create_cls(cls, word_node): """Creates a word from a (lxml.Element) node. [:return:] Word """ cls = super(Word,cls).create_cls(word_node) cls.writing_process_id = int(word_node.get('writing-process-id')) if bool(word_node.get('writing-process-id')) else -1 cls.split_strings = None if bool(word_node.get('split')): cls.split_strings = word_node.get('split').split(' ') if ''.join(cls.split_strings) != cls.text: error_msg = 'Error in file {0}: word with id="{1}" has split attributes that do not correspond to its text attribute!\n'.\ format(word_node.getroottree().docinfo.URL, str(cls.id))\ + 'Split attributes: "{0}".\n'.format(' '.join(cls.split_strings))\ + 'Text attribute: "{0}".\n'.format(cls.text) raise Exception(error_msg) cls.deleted = word_node.get('deleted') == 'true'\ if bool(word_node.get('deleted')) else None cls.word_parts = [ cls.create_cls(node) for node in word_node.xpath('.//' + cls.XML_TAG) ] cls.box_paths = [ Path(node=node) for node in word_node.xpath('.//' + Path.BOX_TAG ) ] earlier_versions = [ cls.create_cls(node) for node in word_node.xpath('.//' + cls.XML_EARLIER_VERSION + '/' + cls.XML_TAG) ] if len(earlier_versions) > 0: cls.earlier_version = earlier_versions[0] return cls @staticmethod def CREATE_WORD(word_node=None, page=None, word_part_objs=[], id=0, height=0, endX=0, endSign=None, matrix=None, line_number=-1, debug_msg=None): """Creates a word from a (lxml.Element) node or word_part_objs. [:return:] Word """ if word_node is not None: # init word from xml node id = int(word_node.get('id')) line_number = int(word_node.get('line-number')) if bool(word_node.get('line-number')) else line_number text = word_node.get('text') deleted = bool(word_node.get('deleted')) and word_node.get('deleted') == 'true' transkription_positions = [ TranskriptionPosition(node=node) for node in word_node.findall('.//' + WordPosition.TRANSKRIPTION) ] faksimile_positions = [ WordPosition(node=node) for node in word_node.findall('.//' + WordPosition.FAKSIMILE) ] word_part_objs = [ item.attrib for item in word_node.findall('.//' + Word.DATA + '/part')]\ if len(word_node.findall('.//' + Word.DATA)) > 0\ else [ item.attrib for item in word_node.findall('.//part')] return Word(id=id, text=text, deleted=deleted, line_number=line_number, transkription_positions=transkription_positions,\ faksimile_positions=faksimile_positions, word_part_objs=word_part_objs) elif len(word_part_objs) > 0: # init word from word_part_obj that has been extracted from svg file WIDTH = 5 TOPCORRECTION = 2.0 FONTWIDTHFACTOR = 0.7 # factor that multiplies lastCharFontSize height = height x = round(float(word_part_objs[0]['x']), 3) if(page is not None and bool(page.style_dict)): HEIGHT_FACTOR = 1.1 # factor that multiplies biggest_font_size -> height style_set = set(' '.join(set( dict['class'] for dict in word_part_objs)).split(' ')) biggest_font_size = page.get_biggest_fontSize4styles(style_set=style_set) height = round(biggest_font_size * HEIGHT_FACTOR + HEIGHT_FACTOR / biggest_font_size, 3) TOPCORRECTION = 1 + HEIGHT_FACTOR / biggest_font_size if endSign is not None and '%' in endSign: lastCharFontSizeList = [ float(page.style_dict[key]['font-size'].replace('px',''))\ for key in word_part_objs[len(word_part_objs)-1]['class'].split(' ')\ if bool(page.style_dict[key].get('font-size'))] lastCharFontSize = lastCharFontSizeList[0] if len(lastCharFontSizeList) > 0 else 1 endX = float(endX) + lastCharFontSize * FONTWIDTHFACTOR elif endSign is not None and '%' in endSign: endX = float(endX) + WIDTH bottom = round(float(word_part_objs[0]['y']), 3) y = round(bottom - height + TOPCORRECTION, 3) width = round(float(endX) - x, 3) transkription_positions = [ WordPosition(height=height, width=width, x=x, y=y, matrix=matrix, tag=WordPosition.TRANSKRIPTION) ] text = ''.join([ dict['text'] for dict in word_part_objs]) line_number = page.get_line_number( (y + bottom)/2) if page is not None else line_number word = Word(id=id, text=text, line_number=line_number, transkription_positions=transkription_positions, word_part_objs=word_part_objs) word.debug_msg = debug_msg return word else: error_msg = 'word_node has not been defined' if (word_node is None) else 'word_part_objs is empty' raise Exception('Error: {}'.format(error_msg)) @classmethod def get_semantic_dictionary(cls): """ Creates and returns a semantic dictionary as specified by SemanticClass. """ dictionary = super(Word,cls).get_semantic_dictionary() dictionary['properties'].update(cls.create_semantic_property_dictionary('deleted', bool,\ name='isWordDeleted', label='has word been deleted')) - dictionary['properties'].update(cls.create_semantic_property_dictionary('writing_process_id',\ - WritingProcess, name='wordBelongsToWritingProcess', label='word has been written in a specific writing process')) + dictionary['properties'].update(cls.create_semantic_property_dictionary('writing_processes', WritingProcess, cardinality=1,\ + cardinality_restriction='minCardinality', name='wordBelongsToWritingProcess', label='word has been written in a specific writing process')) dictionary['properties'].update(cls.create_semantic_property_dictionary('word_parts', list,\ name='wordHasWordParts', label='word has word parts', comment='word consists of a list of words')) return dictionary def execute_function_on_parts(word_parts, func_name): """Execute function on parts and add those parts instead of original word to word_parts. :return: new word_parts, output from func """ copy_parts = word_parts[:] for word in word_parts: output = eval('word.{0}()'.format(func_name)) if len(word.word_parts) > 0: for part_word in word.word_parts: copy_parts.insert(copy_parts.index(word), part_word) copy_parts.remove(word) word.word_parts = [] return copy_parts, output def update_transkription_position_ids(word): """Update transkription_position' ids according to index. """ for index, transkription_position in enumerate(sorted(word.transkription_positions, key=attrgetter('left'))): transkription_position.id = index Index: svgscripts/datatypes/page.py =================================================================== --- svgscripts/datatypes/page.py (revision 68) +++ svgscripts/datatypes/page.py (revision 69) @@ -1,636 +1,655 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ This class can be used to represent a page. """ # Copyright (C) University of Basel 2019 {{{1 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/> 1}}} __author__ = "Christian Steiner" __maintainer__ = __author__ __copyright__ = 'University of Basel' __email__ = "christian.steiner@unibas.ch" __status__ = "Development" __license__ = "GPL v3" __version__ = "0.0.1" from lxml import etree as ET from os.path import isfile from progress.bar import Bar from svgpathtools import svg2paths2, svg_to_paths from svgpathtools.parser import parse_path import sys +import warnings from .box import Box from .image import Image, SVGImage from .faksimile_image import FaksimileImage +from .faksimile_position import FaksimilePosition from .lineNumber import LineNumber +from .line import Line from .mark_foreign_hands import MarkForeignHands from .matrix import Matrix from .path import Path from .positional_word_part import PositionalWordPart from .text_connection_mark import TextConnectionMark +from .text_field import TextField from .transkriptionField import TranskriptionField from .writing_process import WritingProcess from .word import Word from .word_insertion_mark import WordInsertionMark sys.path.append('py2ttl') from class_spec import SemanticClass FILE_TYPE_SVG_WORD_POSITION = 'svgWordPosition' FILE_TYPE_XML_MANUSCRIPT = 'xmlManuscriptFile' class Page(SemanticClass): """ This class represents a page. Args: xml_source_file (str): name of the xml file to be instantiated. xml_target_file (str): name of the xml file to which page info will be written. """ UNITTESTING = False WARNING_MISSING_USE_NODE4PWP = PositionalWordPart.WARN_NO_USE_NODE_FOUND WARNING_MISSING_GLYPH_ID4WIM = WordInsertionMark.WARN_NO_GLYPH_ID PAGE_RECTO = 'recto' PAGE_VERSO = 'verso' def __init__(self, xml_source_file=None, xml_target_file=None, title=None, page_number=None, faksimile_image=None, faksimile_svgFile=None, pdfFile=None, svg_file=None, orientation='North', page_type=PAGE_VERSO, extract_transkription_field_only=True): self.title = title self.mark_foreign_hands = [] self.text_connection_marks = [] self.line_numbers = [] self.style_dict = {} self.sonderzeichen_list = [] self.svg_file = None self.svg_image = None self.pdfFile = None self.faksimile_svgFile = None self.source = None self.number = page_number if page_number is not None else -1 self.orientation = orientation self.page_type = page_type self.word_deletion_paths = [] self.faksimile_image = faksimile_image + self.text_field = None + self.lines = [] if xml_source_file is not None: if isfile(xml_source_file): parser = ET.XMLParser(remove_blank_text=True) self.page_tree = ET.parse(xml_source_file, parser) self.title = self.page_tree.getroot().get('title') self.number = self.page_tree.getroot().get('number') self.source = self.page_tree.getroot().get('source') self.orientation = self.page_tree.getroot().get('orientation') self.page_type = self.page_tree.getroot().get('pageType') - self.init_words() self.add_style(style_node=self.page_tree.getroot().find('.//style')) self.pdfFile = self.page_tree.xpath('.//pdf/@file')[0]\ if len(self.page_tree.xpath('.//pdf/@file')) > 0 else None self.faksimile_svgFile = self.page_tree.xpath('.//faksimile-svg/@file')[0]\ if len(self.page_tree.xpath('.//faksimile-svg/@file')) > 0 else None self.svg_image = SVGImage(node=self.page_tree.xpath('.//' + SVGImage.XML_TAG)[0])\ if len(self.page_tree.xpath('.//' + SVGImage.XML_TAG)) > 0 else None - self.faksimile_image = FaksimileImage(node=self.page_tree.xpath('.//' + FaksimileImage.XML_TAG)[0])\ - if len(self.page_tree.xpath('.//' + FaksimileImage.XML_TAG)) > 0 else None + if len(self.page_tree.xpath('.//' + FaksimileImage.XML_TAG)) > 0: + self.faksimile_image = FaksimileImage(node=self.page_tree.xpath('.//' + FaksimileImage.XML_TAG)[0]) + self.text_field = self.faksimile_image.text_field self.svg_file = self.page_tree.xpath('.//svg/@file')[0]\ if len(self.page_tree.xpath('.//svg/@file')) > 0 else None self.width = float(self.page_tree.xpath('.//svg/@width')[0])\ if len(self.page_tree.xpath('.//svg/@width')) > 0 else 0.0 self.height = float(self.page_tree.xpath('.//svg/@height')[0])\ if len(self.page_tree.xpath('.//svg/@height')) > 0 else 0.0 if pdfFile is not None and self.pdfFile is None: self.pdfFile = pdfFile ET.SubElement(self.page_tree.getroot(), 'pdf', attrib={'file': self.pdfFile}) if faksimile_svgFile is not None and self.faksimile_svgFile is None: self.faksimile_svgFile = faksimile_svgFile ET.SubElement(self.page_tree.getroot(), 'faksimile-svg', attrib={'file': self.faksimile_svgFile}) if faksimile_image is not None: self.faksimile_image = faksimile_image self.faksimile_image.attach_object_to_tree(self.page_tree) if svg_file is not None and self.svg_file is None: self.svg_file = svg_file tf = TranskriptionField(svg_file) self.width = round(tf.documentWidth, 3) self.height = round(tf.documentHeight, 3) self.svg_image = SVGImage(file_name=self.svg_file, width=self.width, height=self.height) self.svg_image.attach_object_to_tree(self.page_tree) if self.svg_image is not None and self.svg_file is None: self.svg_file = self.svg_image.file_name if self.svg_image is not None and self.width == 0.0: self.width = self.svg_image.width if self.svg_image is not None and self.height == 0.0: self.height = self.svg_image.height + self.init_node_objects() else: raise Exception('File "{}" does not exist!'.format(xml_source_file)) elif xml_target_file is not None: self.word_insertion_marks = [] self.words = [] self.writing_processes = [] self.svg_file = svg_file self.pdfFile = pdfFile self.faksimile_svgFile = faksimile_svgFile if isfile(xml_target_file): parser = ET.XMLParser(remove_blank_text=True) self.page_tree = ET.parse(xml_target_file, parser) self.source = self.page_tree.getroot().get('source') if bool(self.page_tree.getroot().get('orientation')): self.orientation = self.page_tree.getroot().get('orientation') elif orientation is not None: self.page_tree.getroot().set('orientation', orientation) if bool(self.page_tree.getroot().get('title')): self.title = self.page_tree.getroot().get('title') elif title is not None: self.page_tree.getroot().set('title', title) if self.svg_file is None: self.svg_file = self.page_tree.xpath('.//svg/@file')[0]\ if len(self.page_tree.xpath('.//svg/@file')) > 0 else None self.width = float(self.page_tree.xpath('.//svg/@width')[0])\ if len(self.page_tree.xpath('.//svg/@width')) > 0 else 0.0 self.height = float(self.page_tree.xpath('.//svg/@height')[0])\ if len(self.page_tree.xpath('.//svg/@height')) > 0 else 0.0 elif len(self.page_tree.xpath('.//svg/@file')) == 0: tf = TranskriptionField(svg_file) self.width = round(tf.documentWidth, 3) self.height = round(tf.documentHeight, 3) self.svg_image = SVGImage(file_name=self.svg_file, width=self.width, height=self.height) self.svg_image.attach_object_to_tree(self.page_tree) #ET.SubElement(self.page_tree.getroot(), 'svg', attrib={'width': str(self.width), 'height': str(self.height), 'file': self.svg_file}) else: self.width = float(self.page_tree.xpath('.//svg/@width')[0])\ if len(self.page_tree.xpath('.//svg/@width')) > 0 else 0.0 self.height = float(self.page_tree.xpath('.//svg/@height')[0])\ if len(self.page_tree.xpath('.//svg/@height')) > 0 else 0.0 if self.pdfFile is None: self.pdfFile = self.page_tree.xpath('.//pdf/@file')[0]\ if len(self.page_tree.xpath('.//pdf/@file')) > 0 else None elif len(self.page_tree.xpath('.//pdf/@file')) == 0: ET.SubElement(self.page_tree.getroot(), 'pdf', attrib={'file': self.pdfFile}) for xpath2remove in [ 'word', 'style', 'freehand', LineNumber.XML_TAG, WordInsertionMark.XML_TAG,\ WritingProcess.XML_TAG, Path.WORD_DELETION_PATH_TAG ]: for node in self.page_tree.xpath('//' + xpath2remove): node.getparent().remove(node) else: self.page_tree = ET.ElementTree(ET.Element('page')) self.pdfFile = pdfFile self.svg_file = svg_file if title is not None: self.page_tree.getroot().set('title', title) if orientation is not None: self.page_tree.getroot().set('orientation', orientation) self.page_tree.getroot().set('transkription-field-only', str(extract_transkription_field_only).lower()) if page_number is not None: self.page_tree.getroot().set('number', str(page_number)) if self.pdfFile is not None: ET.SubElement(self.page_tree.getroot(), 'pdf', attrib={'file': self.pdfFile}) if self.svg_file is not None: tf = TranskriptionField(self.svg_file) self.width = round(tf.documentWidth, 3) self.height = round(tf.documentHeight, 3) self.svg_image = SVGImage(file_name=self.svg_file, width=self.width, height=self.height) self.svg_image.attach_object_to_tree(self.page_tree) #ET.SubElement(self.page_tree.getroot(), 'svg', attrib={'width': str(self.width), 'height': str(self.height), 'file': self.svg_file}) if self.svg_image is None and self.svg_file is not None: self.svg_image = SVGImage(file_name=self.svg_file, width=self.width, height=self.height) self.svg_image.attach_object_to_tree(self.page_tree) def add_style(self, sonderzeichen_list=[], letterspacing_list=[], style_dict={}, style_node=None): """Adds a list of classes that are sonderzeichen and a style dictionary to page. """ self.sonderzeichen_list = sonderzeichen_list self.letterspacing_list = letterspacing_list self.style_dict = style_dict if style_node is not None: self.style_dict = { item.get('name'): { key: value for key, value in item.attrib.items() if key != 'name' } for item in style_node.findall('.//class') } self.sonderzeichen_list = [ item.get('name') for item in style_node.findall('.//class')\ if bool(item.get('font-family')) and 'Sonderzeichen' in item.get('font-family') ] self.letterspacing_list = [ item.get('name') for item in style_node.findall('.//class')\ if bool(item.get('letterspacing-list')) ] elif bool(self.style_dict): style_node = ET.SubElement(self.page_tree.getroot(), 'style') if len(self.sonderzeichen_list) > 0: style_node.set('Sonderzeichen', ' '.join(self.sonderzeichen_list)) if len(self.letterspacing_list) > 0: style_node.set('letterspacing-list', ' '.join(self.letterspacing_list)) for key in self.style_dict.keys(): self.style_dict[key]['name'] = key ET.SubElement(style_node, 'class', attrib=self.style_dict[key]) fontsize_dict = { key: float(value.get('font-size').replace('px','')) for key, value in self.style_dict.items() if 'font-size' in value } fontsizes = sorted(fontsize_dict.values(), reverse=True) # create a mapping between fontsizes and word stages self.fontsizekey2stage_mapping = {} for fontsize_key, value in fontsize_dict.items(): if value >= fontsizes[0]-1: self.fontsizekey2stage_mapping.update({ fontsize_key: WritingProcess.FIRST_VERSION }) elif value <= fontsizes[len(fontsizes)-1]+1: self.fontsizekey2stage_mapping.update({ fontsize_key: WritingProcess.LATER_INSERTION_AND_ADDITION }) else: self.fontsizekey2stage_mapping.update({ fontsize_key: WritingProcess.INSERTION_AND_ADDITION }) def add_source(self, source): """Adds a source to page and attaches it to page_tree. """ self.source = source self.page_tree.getroot().set('source', self.source) def categorize_paths(self, transkription_field=None): """Categorize all paths that are part of the transkription field. :return: a dictionary containig a list for each category of path. """ if self.source is not None and isfile(self.source): MAX_HEIGHT_LINES = 1 max_line = sorted(\ [line_number.bottom-line_number.top for line_number in self.line_numbers if line_number.id % 2 == 0],\ reverse=True)[0] + 2 if len(self.line_numbers) > 0 else 17 tr_xmin = transkription_field.xmin if transkription_field is not None else 0.0 tr_ymin = transkription_field.ymin if transkription_field is not None else 0.0 paths, attributes = svg_to_paths.svg2paths(self.source) allpaths_on_tf = [] allpaths_outside_tf = [] attributes_outside_tf = [] if transkription_field is not None: for index in range(0, len(paths)): path = paths[index] attribute = attributes[index] if len(path) > 0\ and path != transkription_field.path\ and path.bbox()[0] > tr_xmin\ and path.bbox()[1] < transkription_field.xmax: allpaths_on_tf.append(Path(id=index, path=path, style_class=attribute.get('class'))) elif len(path) > 0\ and path != transkription_field.path: allpaths_outside_tf.append(path) attributes_outside_tf.append(attribute) path_dict = { 'text_area_deletion_paths': [],\ 'deletion_or_underline_paths': [],\ 'box_paths': [],\ 'dots_paths': [],\ 'word_connector_paths': [],\ 'uncategorized_paths': [] } for mypath in allpaths_on_tf: xmin, xmax, ymin, ymax = mypath.path.bbox() start_line_number = self.get_line_number(mypath.path.start.imag-tr_ymin) if abs(xmax-xmin) < 1 and abs(ymax-ymin) < 1: path_dict.get('dots_paths').append(mypath) elif abs(ymax-ymin) > MAX_HEIGHT_LINES and abs(ymax-ymin) < max_line and mypath.path.iscontinuous() and mypath.path.isclosed(): path_dict.get('box_paths').append(mypath) elif abs(ymax-ymin) > MAX_HEIGHT_LINES and abs(ymax-ymin) > max_line and mypath.path.iscontinuous() and not mypath.path.isclosed(): path_dict.get('word_connector_paths').append(mypath) elif abs(ymax-ymin) < MAX_HEIGHT_LINES: path_dict.get('deletion_or_underline_paths').append(mypath) elif start_line_number != -1 and start_line_number != self.get_line_number(mypath.path.end.imag-tr_ymin): path_dict.get('text_area_deletion_paths').append(mypath) else: path_dict.get('uncategorized_paths').append(mypath) underline_path = self.mark_words_intersecting_with_paths_as_deleted(path_dict.get('deletion_or_underline_paths'), tr_xmin, tr_ymin) path_dict.update({'underline_path': underline_path}) self.process_word_boxes(path_dict.get('box_paths'), transkription_field,\ paths=allpaths_outside_tf, attributes=attributes_outside_tf, max_line=max_line) return path_dict elif not Page.UNITTESTING: error_msg = 'Svg source file {} does not exist!'.format(self.source)\ if self.source is not None else 'Page does not contain a source file!' raise FileNotFoundError(error_msg) return {} def create_writing_processes_and_attach2tree(self): """Creates three stages of Nietzsche's process of writing. """ self.writing_processes = [ WritingProcess(version=WritingProcess.FIRST_VERSION),\ WritingProcess(version=WritingProcess.INSERTION_AND_ADDITION),\ WritingProcess(version=WritingProcess.LATER_INSERTION_AND_ADDITION) ] for writing_process in self.writing_processes: writing_process.attach_object_to_tree(self.page_tree) for word in self.words: for transkription_position in word.transkription_positions: for font_key in transkription_position.positional_word_parts[0].style_class.split(' '): if font_key in self.fontsizekey2stage_mapping.keys(): transkription_position.writing_process_id = self.fontsizekey2stage_mapping.get(font_key) def find_special_words(self, transkription_field=None): """Find special words, remove them from words, process their content. """ if self.source is None or not isfile(self.source): raise FileNotFoundError('Page does not have a source!') if transkription_field is None: transkription_field = TranskriptionField(self.source) special_char_list = MarkForeignHands.get_special_char_list() special_char_list += TextConnectionMark.get_special_char_list() single_char_words = [ word for word in self.words if len(word.text) == 1 and word.text in special_char_list ] for word in single_char_words: if word.text == MarkForeignHands.CLASS_MARK: id = len(self.mark_foreign_hands) self.mark_foreign_hands.append(MarkForeignHands.create_cls_from_word(word, id=id)) self.words.remove(word) elif word.text in TextConnectionMark.SPECIAL_CHAR_LIST[0]\ or (word.text in TextConnectionMark.SPECIAL_CHAR_LIST\ and any(style in self.sonderzeichen_list for style\ in word.transkription_positions[0].positional_word_parts[0].style_class.split(' '))): id = len(self.text_connection_marks) self.text_connection_marks.append(TextConnectionMark.create_cls_from_word(word, id=id)) self.words.remove(word) svg_tree = ET.parse(self.source) self.update_page_type(transkription_field=transkription_field) self.update_line_number_area(transkription_field, svg_tree=svg_tree) italic_classes = [ key for key in self.style_dict\ if bool(self.style_dict[key].get('font-family')) and self.style_dict[key]['font-family'].endswith('Italic') ] if len(self.mark_foreign_hands) > 0: MarkForeignHands.find_content(self.mark_foreign_hands, transkription_field, svg_tree, italic_classes=italic_classes,\ SonderzeichenList=self.sonderzeichen_list) if len(self.text_connection_marks) > 0: TextConnectionMark.find_content_in_footnotes(self.text_connection_marks, transkription_field, svg_tree,\ title=self.title, page_number=self.number) def get_biggest_fontSize4styles(self, style_set={}): """Returns biggest font size from style_dict for a set of style class names. [:returns:] (float) biggest font size OR 1 if style_dict is empty """ if bool(self.style_dict): sorted_font_sizes = sorted( (float(self.style_dict[key]['font-size'].replace('px','')) for key in style_set if bool(self.style_dict[key].get('font-size'))), reverse=True) return sorted_font_sizes[0] if len(sorted_font_sizes) > 0 else 1 else: return 1 def get_line_number(self, y): """Returns line number id for element at y. [:return:] (int) line number id or -1 """ if len(self.line_numbers) > 0: result_list = [ line_number.id for line_number in self.line_numbers if y >= line_number.top and y <= line_number.bottom ] return result_list[0] if len(result_list) > 0 else -1 else: return -1 @classmethod def get_pages_from_xml_file(cls, xml_file, status_contains='', word_selection_function=None): """Returns a list of Page instantiating a xml_file of type FILE_TYPE_SVG_WORD_POSITION or xml_files contained in xml_file of type FILE_TYPE_XML_MANUSCRIPT. [optional: instantiation depends on the fulfilment of a status_contains and/or on the selection of some words by a word_selection_function]. """ source_tree = ET.parse(xml_file) if source_tree.getroot().find('metadata/type').text == FILE_TYPE_SVG_WORD_POSITION: page = cls(xml_source_file=xml_file) if word_selection_function is None or len(word_selection_function(page.words)) > 0: return [ page ] else: return [] elif source_tree.getroot().find('metadata/type').text == FILE_TYPE_XML_MANUSCRIPT: pages = [] xpath = '//page/@output'\ if status_contains == ''\ else '//page[contains(@status, "{0}")]/@output'.format(status_contains) for xml_source_file in source_tree.xpath(xpath): if isfile(xml_source_file): pages += cls.get_pages_from_xml_file(xml_source_file, word_selection_function=word_selection_function) return pages else: return [] @classmethod def get_semantic_dictionary(cls): """ Creates a semantic dictionary as specified by SemanticClass. """ dictionary = {} class_dict = cls.get_class_dictionary() properties = { 'number': { 'class': str, 'cardinality': 1},\ 'faksimile_image': { 'class': FaksimileImage, 'cardinality': 1},\ 'orientation': { 'class': str, 'cardinality': 1},\ 'svg_image': { 'class': SVGImage, 'cardinality': 1}} - for key in [ 'line_numbers', 'words', 'writing_processes', 'word_deletion_paths', 'word_insertion_marks']: + properties.update(cls.create_semantic_property_dictionary('text_field', TextField,\ + cardinality=1, name='pageIsOnTextField', label='page is on text field',\ + comment='Relates a page to the text field on a faksimile image.')) + for key in [ 'lines', 'words', 'writing_processes', 'word_deletion_paths', 'word_insertion_marks']: properties.update(cls.create_semantic_property_dictionary(key, list)) dictionary.update({'class': class_dict}) dictionary.update({'properties': properties}) return dictionary def init_line_numbers(self, line_numbers, document_bottom): """Init line numbers. """ even_index = 0 MINABOVE = 1 self.line_numbers = [] if len(line_numbers) > 0: first_line_bottom = line_numbers[even_index].top - MINABOVE self.line_numbers.append(LineNumber(id=1, top=0, bottom=first_line_bottom)) self.line_numbers.append(line_numbers[even_index]) even_index += 1 while even_index < len(line_numbers): self.line_numbers.append(LineNumber(id=line_numbers[even_index].id-1,\ top=line_numbers[even_index-1].bottom+MINABOVE,\ bottom=line_numbers[even_index].top-MINABOVE)) self.line_numbers.append(line_numbers[even_index]) even_index += 1 self.line_numbers.append(LineNumber(id=line_numbers[even_index-1].id+1,\ top=line_numbers[even_index-1].bottom+MINABOVE,\ bottom=document_bottom)) for line_number in self.line_numbers: line_number.attach_object_to_tree(self.page_tree) - def init_words(self): + def init_node_objects(self): + """Initialize all node objects. + """ self.word_insertion_marks = [ WordInsertionMark(wim_node=wim_node) for wim_node in self.page_tree.getroot().xpath('//' + WordInsertionMark.XML_TAG) ] self.words = [ Word.create_cls(word_node) for word_node in self.page_tree.getroot().xpath('./word') ] self.mark_foreign_hands = [ MarkForeignHands.create_cls(node) for node in self.page_tree.getroot().xpath('//' + MarkForeignHands.XML_TAG) ] self.text_connection_marks = [ TextConnectionMark.create_cls(node) for node in self.page_tree.getroot().xpath('//' + TextConnectionMark.XML_TAG) ] self.line_numbers = [ LineNumber(xml_text_node=line_number_node) for line_number_node in self.page_tree.getroot().xpath('//' + LineNumber.XML_TAG) ] + self.lines = [ Line.create_cls_from_node(node=line_number_node) for line_number_node in self.page_tree.getroot().xpath('//' + LineNumber.XML_TAG) ] self.writing_processes = [ WritingProcess.create_writing_process_from_xml(node, self.words) for node in self.page_tree.xpath('//' + WritingProcess.XML_TAG) ] self.word_deletion_paths = [ Path(node=node) for node in self.page_tree.xpath('//' + Path.WORD_DELETION_PATH_TAG) ] + if self.faksimile_image is not None and self.text_field is not None: + for simple_word in self.words + self.mark_foreign_hands + self.text_connection_marks: + simple_word.init_word(self) + for wim in self.word_insertion_marks: + if wim.line_number > -1: + wim.line = [ line for line in self.lines if line.id == wim.line_number ][0] def is_locked(self): """Return true if page is locked. """ return len(self.page_tree.xpath('//metadata/lock')) > 0 def lock(self, reference_file, message=''): """Lock tree such that ids of words etc. correspond to ids in reference_file, optionally add a message that will be shown. """ if not self.is_locked(): metadata = self.page_tree.xpath('./metadata')[0]\ if len(self.page_tree.xpath('./metadata')) > 0\ else ET.SubElement(self.page_tree.getroot(), 'metadata') lock = ET.SubElement(metadata, 'lock') ET.SubElement(lock, 'reference-file').text = reference_file if message != '': ET.SubElement(lock, 'message').text = message def mark_words_intersecting_with_paths_as_deleted(self, deletion_paths, tr_xmin=0.0, tr_ymin=0.0): """Marks all words that intersect with deletion paths as deleted and adds these paths to word_deletion_paths. [:return:] list of .path.Path that might be word_underline_paths """ if not Page.UNITTESTING: bar = Bar('mark words that intersect with deletion paths', max=len(self.words)) for word in self.words: not bool(Page.UNITTESTING) and bar.next() word.deleted = False for transkription_position in word.transkription_positions: word_path = Path.create_path_from_transkription_position(transkription_position,\ tr_xmin=tr_xmin, tr_ymin=tr_ymin) intersecting_paths = [ deletion_path for deletion_path in deletion_paths\ if do_paths_intersect_saveMode(deletion_path.path, word_path.path) ] if len(intersecting_paths) > 0: transkription_position.deleted = True for deletion_path in intersecting_paths: if deletion_path not in self.word_deletion_paths: deletion_path.tag = Path.WORD_DELETION_PATH_TAG deletion_path.attach_object_to_tree(self.page_tree) self.word_deletion_paths.append(deletion_path) word.partition_according_to_writing_process_id() word.partition_according_to_deletion() not bool(Page.UNITTESTING) and bar.finish() # return those paths in deletion_paths that are not in self.word_deletion_paths return [ word_underline_path for word_underline_path in set(deletion_paths) - set(self.word_deletion_paths) ] def process_word_boxes(self, box_paths, transkription_field, paths=None, attributes=None, max_line=17): """Process word boxes: partition words according to word boxes. """ MAX_HEIGHT_LINES = 1 if not Page.UNITTESTING: bar = Bar('process word boxes', max=len(self.words)) svg_tree = ET.parse(self.source) namespaces = { k if k is not None else 'ns': v for k, v in svg_tree.getroot().nsmap.items() } allpaths_on_margin_field = [] if paths is None or attributes is None: paths, attributes = svg_to_paths.svg2paths(self.source) for index in range(0, len(paths)): path = paths[index] xmin, xmax, ymin, ymax = path.bbox() attribute = attributes[index] if len(path) > 0\ and path != transkription_field.path\ and ((path.bbox()[1] < transkription_field.xmin and transkription_field.is_page_verso())\ or (path.bbox()[0] > transkription_field.xmax and not transkription_field.is_page_verso()))\ and abs(ymax-ymin) < max_line: allpaths_on_margin_field.append(Path(id=index, path=path, style_class=attribute.get('class'))) box_line_number_dict = {} for box_path in sorted(box_paths, key=lambda path: path.get_median_y()): line_number = self.get_line_number(box_path.get_median_y(tr_ymin=transkription_field.ymin)) if line_number not in box_line_number_dict.keys(): box_line_number_dict.update({ line_number: [ box_path ]}) else: box_line_number_dict.get(line_number).append(box_path) boxes = [] for line_number in box_line_number_dict.keys(): box_paths_on_line = sorted(box_line_number_dict[line_number], key=lambda path: path.get_x()) margin_boxes_on_line = sorted([ margin_box for margin_box in allpaths_on_margin_field\ if self.get_line_number(margin_box.get_median_y(tr_ymin=transkription_field.ymin)) == line_number ],\ key=lambda path: path.get_x()) threshold = 3 if line_number % 2 == 0 else 1.5 for box_path in box_paths_on_line: box = Box.create_box(box_path, margin_boxes_on_line, svg_tree=svg_tree,\ transkription_field=transkription_field, namespaces=namespaces, threshold=threshold) if box is not None: boxes.append(box) for word in self.words: not bool(Page.UNITTESTING) and bar.next() word.process_boxes(boxes, tr_xmin=transkription_field.xmin, tr_ymin=transkription_field.ymin) not bool(Page.UNITTESTING) and bar.finish() def unlock(self): """Lock tree such that ids of words etc. correspond to ids in reference_file, optionally add a message that will be shown. """ if self.is_locked(): lock = self.page_tree.xpath('//metadata/lock')[0] lock.getparent().remove(lock) def update_and_attach_words2tree(self, update_function_on_word=None, include_special_words_of_type=[]): """Update word ids and attach them to page.page_tree. """ if not self.is_locked(): update_function_on_word = [ update_function_on_word ]\ if type(update_function_on_word) != list\ else update_function_on_word for node in self.page_tree.xpath('.//word|.//' + MarkForeignHands.XML_TAG + '|.//' + TextConnectionMark.XML_TAG): node.getparent().remove(node) for index, word in enumerate(self.words): word.id = index for func in update_function_on_word: if callable(func): func(word) word.attach_word_to_tree(self.page_tree) for index, mark_foreign_hands in enumerate(self.mark_foreign_hands): mark_foreign_hands.id = index if MarkForeignHands in include_special_words_of_type: for func in update_function_on_word: if callable(update_function_on_word): func(mark_foreign_hands) mark_foreign_hands.attach_word_to_tree(self.page_tree) for index, text_connection_mark in enumerate(self.text_connection_marks): text_connection_mark.id = index if TextConnectionMark in include_special_words_of_type: for func in update_function_on_word: if callable(update_function_on_word): func(text_connection_mark) text_connection_mark.attach_word_to_tree(self.page_tree) else: print('locked') def update_line_number_area(self, transkription_field, svg_tree=None): """Determines the width of the area where the line numbers are written in the page.source file. """ THRESHOLD = 0.4 if svg_tree is None: svg_tree = ET.parse(self.source) if len(self.line_numbers) > 1: line_number = self.line_numbers[9]\ if transkription_field.is_page_verso() and len(self.line_numbers) > 8\ else self.line_numbers[1] ln_nodes = [ item for item in svg_tree.iterfind('//text', svg_tree.getroot().nsmap)\ if Matrix.IS_NEARX_TRANSKRIPTION_FIELD(item.get('transform'), transkription_field)\ and LineNumber.IS_A_LINE_NUMBER(item)\ and LineNumber(raw_text_node=item, transkription_field=transkription_field).id == line_number.id ] if len(ln_nodes) > 0: matrix = Matrix(transform_matrix_string=ln_nodes[0].get('transform')) if transkription_field.is_page_verso(): transkription_field.add_line_number_area_width(matrix.getX()) elif self.svg_file is not None and isfile(self.svg_file): svg_path_tree = ET.parse(self.svg_file) namespaces = { k if k is not None else 'ns': v for k, v in svg_path_tree.getroot().nsmap.items() } svg_x = matrix.getX() svg_y = self.line_numbers[1].bottom + transkription_field.ymin use_nodes = svg_path_tree.xpath('//ns:use[@x>="{0}" and @x<="{1}" and @y>="{2}" and @y<="{3}"]'\ .format(svg_x-THRESHOLD, svg_x+THRESHOLD,svg_y-THRESHOLD, svg_y+THRESHOLD), namespaces=namespaces) if len(use_nodes) > 0: symbol_id = use_nodes[0].get('{%s}href' % namespaces['xlink']).replace('#', '') d_strings = use_nodes[0].xpath('//ns:symbol[@id="{0}"]/ns:path/@d'.format(symbol_id), namespaces=namespaces) if len(d_strings) > 0 and d_strings[0] != '': path = parse_path(d_strings[0]) xmin, xmax, ymin, ymax = path.bbox() width = xmax - xmin transkription_field.add_line_number_area_width(matrix.getX() + width) def update_page_type(self, transkription_field=None): """Adds a source to page and attaches it to page_tree. """ if transkription_field is None: if self.source is None or not isfile(self.source): raise FileNotFoundError('Page does not have a source!') transkription_field = TranskriptionField(self.source) self.page_type = Page.PAGE_VERSO\ if transkription_field.is_page_verso()\ else Page.PAGE_RECTO self.page_tree.getroot().set('pageType', self.page_type) def do_paths_intersect_saveMode(path1, path2): """Returns true if paths intersect, false if not or if there was an exception. """ try: return path1.intersect(path2, justonemode=True) except AssertionError: return False Index: svgscripts/datatypes/text_connection_mark.py =================================================================== --- svgscripts/datatypes/text_connection_mark.py (revision 68) +++ svgscripts/datatypes/text_connection_mark.py (revision 69) @@ -1,93 +1,92 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ This class can be used to represent a text connection mark ("Anschlusszeichen"). """ # Copyright (C) University of Basel 2019 {{{1 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/> 1}}} __author__ = "Christian Steiner" __maintainer__ = __author__ __copyright__ = 'University of Basel' __email__ = "christian.steiner@unibas.ch" __status__ = "Development" __license__ = "GPL v3" __version__ = "0.0.1" from lxml import etree as ET import sys from .footnotes import extract_footnotes_as_strings -from .lineNumber import LineNumber from .reference import Reference from .special_word import SpecialWord class TextConnectionMark(SpecialWord): """ This class represents a text connection mark. """ XML_TAG = 'text-connection-mark' XML_SUB_TAG = Reference.XML_TAG SPECIAL_CHAR_LIST = [ '*', 'W' ] def __init__(self, id=0, line_number=-1, text='*', transkription_positions=[], faksimile_positions=[], text_source=None): super(TextConnectionMark, self).__init__(id=id, text=text, line_number=line_number, transkription_positions=transkription_positions,\ faksimile_positions=faksimile_positions) self.text_source = text_source def add_content(self, node): """Adds content to TextConnectionMark. """ self.text_source = Reference.create_cls(node=node) def attach_word_to_tree(self, target_tree): """Attaches TextConnectionMark to tree target_tree. """ node = super(TextConnectionMark,self).attach_word_to_tree(target_tree) if self.text_source is not None: self.text_source.attach_object_to_tree(node) @staticmethod def find_content_in_footnotes(list_of_text_connection_marks, transkription_field, svg_tree, title='', page_number=''): """Find content for the TextConnectionMark. """ footnotes = extract_footnotes_as_strings(transkription_field=transkription_field, svg_tree=svg_tree, contains_string='Anschlußzeichen') for text_connection_mark in list_of_text_connection_marks: relevant_footnotes = [ footnote_string for footnote_string in footnotes if footnote_string.strip().startswith(str(text_connection_mark.line_number)+ ':') ] if len(relevant_footnotes) > 0: footnote_string = relevant_footnotes[0].strip() line_number = int(footnote_string.split(':')[0]) is_uncertain = footnote_string.endswith('?') reference_string = footnote_string.replace('?', '').split('zu')[1].strip() text_connection_mark.text_source = Reference.create_cls(is_uncertain=is_uncertain,\ reference_string=reference_string, title=title, page_number=page_number) @classmethod def get_semantic_dictionary(cls): """ Creates a semantic dictionary as specified by SemanticClass. """ dictionary = super(TextConnectionMark,cls).get_semantic_dictionary() dictionary['properties'].update(cls.create_semantic_property_dictionary('text_source', Reference,\ cardinality=1, name='textConnectionMarkHasTextSource', label='text connection mark has a text source')) return dictionary @classmethod def get_special_char_list(cls): """Returns a list of the chars that define this special word. """ return cls.SPECIAL_CHAR_LIST Index: svgscripts/datatypes/word_insertion_mark.py =================================================================== --- svgscripts/datatypes/word_insertion_mark.py (revision 68) +++ svgscripts/datatypes/word_insertion_mark.py (revision 69) @@ -1,137 +1,138 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ This class can be used to represent a word insertion mark. """ # Copyright (C) University of Basel 2019 {{{1 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/> 1}}} __author__ = "Christian Steiner" __maintainer__ = __author__ __copyright__ = 'University of Basel' __email__ = "christian.steiner@unibas.ch" __status__ = "Development" __license__ = "GPL v3" __version__ = "0.0.1" from lxml import etree as ET from svgpathtools.parser import parse_path import warnings -from .lineNumber import LineNumber +from .line import Line from .positional_object import PositionalObject from .word import Word class WordInsertionMark(PositionalObject): """ This class represents a word insertion mark. Args: wim_node (etree.Element): element that contains information about a word_insertion_mark. OR id (int): word id x (float) y (float) height (float) width (float) previous_word_id (int): id of the word to which word insertion mark is attached inserted_words: Array->Word of inserted words marked by the word insertion mark. """ WARN_NO_GLYPH_ID = 'No glyph_id found' XML_TAG = 'word-insertion-mark' extraStringKeys = [ 'mark_type', 'symbol_id' ] def __init__(self, wim_node=None, id=0, x=-1.0, y=-1.0, height=0, width=0, previous_word_id=-1, next_word_id=-1, line_number=-1, symbol_id=None, inserted_words=[], inserted_word_id=-1, mark_type='A'): super(WordInsertionMark, self).__init__(id=id, node=wim_node, height=height, width=width, x=x, y=y, tag=WordInsertionMark.XML_TAG) self.stringKeys += [ 'mark_type', 'symbol_id' ] self.intKeys += [ 'line_number', 'next_word_id', 'previous_word_id' ] self.symbol_id = symbol_id self.mark_type = mark_type self.line_number = line_number + self.line = None self.previous_word_id = previous_word_id self.next_word_id = next_word_id if wim_node is not None: self.mark_type = wim_node.get('mark-type') self.line_number = int(wim_node.get('line-number')) if bool(wim_node.get('line-number')) else -1 self.previous_word_id = int(wim_node.get('previous-word-id')) if bool(wim_node.get('previous-word-id')) else -1 self.next_word_id = int(wim_node.get('next-word-id')) if bool(wim_node.get('next-word-id')) else -1 def init_inserted_words(self, inserted_words=[], wim_node=None, inserted_word_id_string=None): if wim_node is not None and inserted_word_id_string is not None: ids = inserted_word_id_string.split(' ') inserted_words = [ Word.CREATE_WORD(word_node=word_node) for word_node in wim_node.getroottree().getroot().xpath('.//word[@id>="{0}" and @id<="{1}"]'.format(ids[0], ids[len(ids)-1])) ] if len(inserted_words) > 0: inserted_words[0].is_head_of_inserted_words = True inserted_words[len(inserted_words)-1].is_tail_of_inserted_words = True for word in inserted_words: word.set_word_insertion_mark(self) return inserted_words def attach_and_update_word_if_involved(self, word): if word.id == self.previous_word_id: word.is_before_inserted_words = True word.word_insertion_mark = self elif word.id == self.next_word_id: word.is_after_inserted_words = True word.word_insertion_mark = self elif word.id in [ inserted.id for inserted in self.inserted_words ]: word = [ inserted for inserted in self.inserted_words if inserted.id == word.id ][0] return word @classmethod def get_semantic_dictionary(cls): """ Creates a semantic dictionary as specified by SemanticClass. """ dictionary = super(cls,cls).get_semantic_dictionary() word_dicts = { key: { 'class': Word, 'cardinality': 1, 'cardinality_restriction': 'maxCardinality',\ 'label': 'has {} word'.format(key.replace('_word_id','')),\ 'name': 'has{}'.format(key.title().replace('_Id','').replace('_','')) }\ for key in [ 'previous_word_id', 'next_word_id' ] } dictionary['properties'].update(word_dicts) - dictionary['properties'].update({'line_number': {'class': LineNumber, 'cardinality': 1,\ - 'name': 'wordInsertionMarkHasLineNumber', 'label': 'word insertion mark has a line number'}}) + dictionary['properties'].update({'line': {'class': Line, 'cardinality': 1,\ + 'name': 'wordInsertionMarkBelongsToLine', 'label': 'word insertion mark belongs to a specific line'}}) for extraStringKey in cls.extraStringKeys: dictionary['properties'].update(cls.create_semantic_property_dictionary(extraStringKey, str, cardinality=1)) return dictionary @staticmethod def CREATE_WORD_INSERTION_MARK(svg_path_tree, namespaces, id=0, x=0.0, y=0.0, xmin=0.0, ymin=0.0, line_number=-1, mark_type='A'): """Creates a (datatypes.word_insertion_mark) WordInsertionMark using a (lxml.ElementTree) svg_path_tree and the corresponding namespaces. """ THRESHOLD = 0.4 svg_x = x + xmin svg_y = y + ymin use_nodes = svg_path_tree.xpath('//ns:use[@x>="{0}" and @x<="{1}" and @y>="{2}" and @y<="{3}"]'\ .format(svg_x-THRESHOLD, svg_x+THRESHOLD,svg_y-THRESHOLD, svg_y+THRESHOLD), namespaces=namespaces) if len(use_nodes) > 0: symbol_id = use_nodes[0].get('{%s}href' % namespaces['xlink']).replace('#', '') d_strings = use_nodes[0].xpath('//ns:symbol[@id="{0}"]/ns:path/@d'.format(symbol_id), namespaces=namespaces) height = 0.0 width = 0.0 if len(d_strings) > 0 and d_strings[0] != '': path = parse_path(d_strings[0]) xmin, xmax, ymin, ymax = path.bbox() width = xmax - xmin height = ymax - ymin return WordInsertionMark(id=id, x=x, y=y-height, height=height, width=width, line_number=line_number,\ mark_type=mark_type, symbol_id=symbol_id) else: warnings.warn('{} for word insertion mark {} on line {}'.format(WordInsertionMark.WARN_NO_GLYPH_ID, id, line_number)) return WordInsertionMark(id=id, x=x, y=y, line_number=line_number, mark_type=mark_type) Index: svgscripts/datatypes/simple_word.py =================================================================== --- svgscripts/datatypes/simple_word.py (revision 68) +++ svgscripts/datatypes/simple_word.py (revision 69) @@ -1,109 +1,118 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ This super class can be used to represent a simple word. """ # Copyright (C) University of Basel 2019 {{{1 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/> 1}}} __author__ = "Christian Steiner" __maintainer__ = __author__ __copyright__ = 'University of Basel' __email__ = "christian.steiner@unibas.ch" __status__ = "Development" __license__ = "GPL v3" __version__ = "0.0.1" import abc from lxml import etree as ET import sys -from .lineNumber import LineNumber +from .line import Line +from .faksimile_position import FaksimilePosition from .transkription_position import TranskriptionPosition from .word_position import WordPosition sys.path.append('py2ttl') from class_spec import SemanticClass class SimpleWord(SemanticClass, metaclass=abc.ABCMeta): """ This class represents a simple word. """ XML_TAG = 'simple-word' XML_SUB_TAG = 'content' - def __init__(self, id=0, line_number=-1, text='', deleted=False, transkription_positions=None, faksimile_positions=None): + def __init__(self, id=0, line_number=-1, line=None, text='', deleted=False, transkription_positions=None, faksimile_positions=None): self.id = id self.text = text self.line_number = line_number + self.lines = [] + if line is not None: + self.lines.append(line) self.transkription_positions = transkription_positions if transkription_positions is not None else [] self.faksimile_positions = faksimile_positions if faksimile_positions is not None else [] def attach_word_to_tree(self, target_tree): """Attaches word to tree target_tree. """ if target_tree.__class__.__name__ == '_ElementTree': target_tree = target_tree.getroot() if len(target_tree.xpath('.//' + self.XML_TAG + '[@id="%s"]' % self.id)) > 0: word_node = target_tree.xpath('.//' + self.XML_TAG + '[@id="%s"]' % self.id)[0] word_node.getparent().remove(word_node) word_node = ET.SubElement(target_tree, self.XML_TAG, attrib={'id': str(self.id)}) word_node.set('text', self.text) if self.line_number > -1: word_node.set('line-number', str(self.line_number)) for transkription_position in self.transkription_positions: transkription_position.attach_object_to_tree(word_node) for faksimile_position in self.faksimile_positions: faksimile_position.attach_object_to_tree(word_node) return word_node @classmethod def create_cls(cls, word_node): """Creates a cls from a (lxml.Element) node. [:return:] cls """ if word_node is not None: # init word from xml node id = int(word_node.get('id')) line_number = int(word_node.get('line-number')) if bool(word_node.get('line-number')) else -1 text = word_node.get('text') transkription_positions = [ TranskriptionPosition(node=node) for node in word_node.findall('.//' + WordPosition.TRANSKRIPTION) ] faksimile_positions = [ WordPosition(node=node) for node in word_node.findall('.//' + WordPosition.FAKSIMILE) ] return cls(id=id, text=text, line_number=line_number, transkription_positions=transkription_positions,\ faksimile_positions=faksimile_positions) else: error_msg = 'word_node has not been defined' raise Exception('Error: {}'.format(error_msg)) @classmethod def get_semantic_dictionary(cls): """ Creates and returns a semantic dictionary as specified by SemanticClass. """ dictionary = {} class_dict = cls.get_class_dictionary() - # What about the cardinality of hasLineNumber? If a word has parts on different lines, does it have more than one line_number or none? - properties = { 'line_number': {'class': LineNumber, 'cardinality': 1,\ + properties = { 'lines': {'class': Line, 'cardinality': 1,\ 'cardinality_restriction': 'minCardinality',\ - 'name': 'wordHasLineNumber',\ - 'label': 'word has a line number',\ - 'comment': 'Relating a word to a line number it has.'}} + 'name': 'wordBelongsToLine',\ + 'label': 'word belongs to a line',\ + 'comment': 'Relating a word to a line.'}} properties.update(cls.create_semantic_property_dictionary('transkription_positions', list, cardinality=1, cardinality_restriction='minCardinality')) properties.update(cls.create_semantic_property_dictionary('faksimile_positions', list, cardinality=1, cardinality_restriction='minCardinality')) properties.update(cls.create_semantic_property_dictionary('text', str, cardinality=1)) dictionary.update({'class': class_dict}) dictionary.update({'properties': properties}) return dictionary + def init_word(self, page): + """Initialize word with objects from page. + """ + self.faksimile_positions = FaksimilePosition.create_list_of_cls(self.faksimile_positions, page.faksimile_image, page.text_field) + if self.line_number > -1: + self.lines += [ line for line in page.lines if line.id == self.line_number ] Index: svgscripts/datatypes/line.py =================================================================== --- svgscripts/datatypes/line.py (revision 0) +++ svgscripts/datatypes/line.py (revision 69) @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" This class can be used to represent a line. +""" +# Copyright (C) University of Basel 2019 {{{1 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/> 1}}} + +__author__ = "Christian Steiner" +__maintainer__ = __author__ +__copyright__ = 'University of Basel' +__email__ = "christian.steiner@unibas.ch" +__status__ = "Development" +__license__ = "GPL v3" +__version__ = "0.0.1" + +import re +from lxml import etree as ET +from os.path import isfile +import sys + +from .matrix import Matrix + +sys.path.append('py2ttl') +from class_spec import SemanticClass + +class Line(SemanticClass): + """ + This class represents a line on a page. + @label a line on a page + + Args: + id (int) + bottom (float) + top (float) + """ + XML_TAG = 'line-number' + WARN_NO_LINE_NUMBER = 'No line number found' + + def __init__(self, id=0, bottom=0.0, top=0.0): + self.id = id + self.is_even = self.id % 2 == 0 + self.bottom = bottom + self.top = top + + @classmethod + def create_cls_from_node(cls, node): + """Create a cls from node. + """ + id = int(node.get('id')) if bool(node.get('id')) else 0 + bottom = float(node.get('bottom')) if bool(node.get('bottom')) else 0.0 + top = float(node.get('top')) if bool(node.get('top')) else 0.0 + return cls(id=id, bottom=bottom, top=top) + + @classmethod + def get_semantic_dictionary(cls) -> dict: + """ Creates and returns a semantic dictionary as specified by SemanticClass. + """ + dictionary = {} + class_dict = cls.get_class_dictionary() + properties = { 'id': { 'class': int, 'cardinality': 1,\ + 'name': 'lineHasNumber', 'label': 'line has number',\ + 'comment': 'Relating a line to the number it has.'}} + properties.update(cls.create_semantic_property_dictionary('bottom', float, cardinality=1)) + properties.update(cls.create_semantic_property_dictionary('top', float, cardinality=1)) + properties.update(cls.create_semantic_property_dictionary('is_even', bool, cardinality=1,\ + name='isMainLine', label='whether or not line is a main line',\ + comment='Indicates whether or not line is a main line. Lines that are not main lines, contain later inserted words.')) + dictionary.update({'class': class_dict}) + dictionary.update({'properties': properties}) + return dictionary + + Index: svgscripts/datatypes/faksimile_position.py =================================================================== --- svgscripts/datatypes/faksimile_position.py (revision 0) +++ svgscripts/datatypes/faksimile_position.py (revision 69) @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" This class can be used to represent a faksimile word position. +""" +# Copyright (C) University of Basel 2019 {{{1 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/> 1}}} + +__author__ = "Christian Steiner" +__maintainer__ = __author__ +__copyright__ = 'University of Basel' +__email__ = "christian.steiner@unibas.ch" +__status__ = "Development" +__license__ = "GPL v3" +__version__ = "0.0.1" + +from lxml import etree as ET + +from .faksimile_image import FaksimileImage +from .matrix import Matrix +from .positional_object import PositionalObject +from .text_field import TextField +from .writing_process import WritingProcess +from .word_position import WordPosition + +class FaksimilePosition(WordPosition): + """ + This class represents the position of a Word on a TextField on a FaksimileImage. + + Args: + id (int): word id + matrix (Matrix): matrix containing information about conversion. + height (float): height of word + width (float): width of word + x (float): x position of word + y (float): y position of word + faksimile_image (FaksimileImage) the faksimile image + text_field (TextField) the text_field on the faksimile_image. + """ + XML_TAG = 'faksimile-position' + + def __init__(self, id=0, node=None, text=None, height=0.0, width=0.0, x=0.0, y=0.0, matrix=None, faksimile_image=None, text_field=None): + super(FaksimilePosition, self).__init__(id=id, node=node, height=height, width=width, x=x, y=y, matrix=matrix, tag=WordPosition.FAKSIMILE) + self.faksimile_image = faksimile_image + self.text_field = text_field + if self.text_field is None\ + and self.faksimile_image is not None\ + and self.faksimile_image.text_field is not None: + self.text_field = self.faksimile_image.text_field + + @classmethod + def get_semantic_dictionary(cls): + """ Creates a semantic dictionary as specified by SemanticClass. + """ + dictionary = super(FaksimilePosition,cls).get_semantic_dictionary() + dictionary['properties'].update(cls.create_semantic_property_dictionary('faksimile_image',\ + FaksimileImage, cardinality=1, name='isOnFaksimileImage', label='faksimile position is on faksimile image',\ + comment='Relates the faksimile position of a word to the faksimile image')) + dictionary['properties'].update(cls.create_semantic_property_dictionary('text_field',\ + TextField, cardinality=1, name='isOnTextField', label='faksimile position is on text field',\ + comment='Relates the faksimile position of a word to its text field on a faksimile image')) + return dictionary + + @classmethod + def create_list_of_cls(cls, word_positions, faksimile_image, text_field): + """Instantiate cls from a list of WordPosition by adding FaksimileImage and TextField. + """ + return [ cls(id=wp.id, height=wp.height, width=wp.width, x=wp.left, y=wp.top, matrix=wp.transform,\ + faksimile_image=faksimile_image, text_field=text_field)\ + for wp in word_positions ] + Index: svgscripts/datatypes/transkription_position.py =================================================================== --- svgscripts/datatypes/transkription_position.py (revision 68) +++ svgscripts/datatypes/transkription_position.py (revision 69) @@ -1,188 +1,190 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ This class can be used to represent a transkription word position. """ # Copyright (C) University of Basel 2019 {{{1 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/> 1}}} __author__ = "Christian Steiner" __maintainer__ = __author__ __copyright__ = 'University of Basel' __email__ = "christian.steiner@unibas.ch" __status__ = "Development" __license__ = "GPL v3" __version__ = "0.0.1" from lxml import etree as ET from os.path import isfile import sys from .debug_message import DebugMessage from .image import SVGImage from .positional_word_part import PositionalWordPart from .word_position import WordPosition from .matrix import Matrix sys.path.append('py2ttl') from class_spec import SemanticClass class TranskriptionPosition(WordPosition): """ - This class represents a transkription word position. + This class represents the position of a word on the transkription as it is displayed by a svg image. + @label position of a word on the topological transkription Args: id (int): word id matrix (datatypes.Matrix): matrix containing information about transformation. height (float): height of word width (float): width of word x (float): x position of word y (float): y position of word positional_word_parts a list of (datatypes.positional_word_part) PositionalWordPart debug_message a (datatypes.debug_message) DebugMessage """ ADD2X = 0.15 ADD2TOP = 1.0 ADD2BOTTOM = 0.2 HEIGHT_FACTOR = 1.1 # factor that multiplies biggest_font_size -> height XML_TAG = WordPosition.TRANSKRIPTION def __init__(self, id=0, node=None, height=0.0, width=0.0, x=0.0, y=0.0, matrix=None, positional_word_parts=None, debug_message=None): super(TranskriptionPosition, self).__init__(id=id, node=node, height=height, width=width, x=x, y=y, matrix=matrix, tag=WordPosition.TRANSKRIPTION) self.positional_word_parts = positional_word_parts if positional_word_parts is not None else [] self.debug_message = debug_message self.deleted = False self.has_box = None self.svg_image = None if node is not None: self.debug_message = DebugMessage(node=node.xpath('.//' + DebugMessage.XML_TAG)[0])\ if len(node.xpath('.//' + DebugMessage.XML_TAG)) > 0 else None self.positional_word_parts = [ PositionalWordPart(node=pwp_node) for pwp_node in node.xpath('.//' + PositionalWordPart.XML_TAG) ] self.attachable_objects += self.positional_word_parts if self.debug_message is not None: self.attachable_objects.append(self.debug_message) @classmethod def get_semantic_dictionary(cls): """ Creates a semantic dictionary as specified by SemanticClass. """ dictionary = super(TranskriptionPosition,cls).get_semantic_dictionary() #dictionary['properties'].update({'positional_word_parts': (PositionalWordPart, SemanticClass.LIST, '{}/@id'.format(cls.XML_TAG))}) - dictionary['properties'].update(cls.create_semantic_property_dictionary('svg_image', SVGImage, cardinality=1)) + dictionary['properties'].update(cls.create_semantic_property_dictionary('svg_image', SVGImage, cardinality=1,\ + name='isOnSvgImage', label='transkription position is on svg image')) return dictionary def get_text(self): """Returns the concatenated text of all positional_word_parts. """ return ''.join([pwp.text for pwp in self.positional_word_parts]) def split(self, split_position, second_split=-1): """Split a transkription_position in two at split_position. :return: a list of the new transkription_positions """ transkription_positions = [] left_pwp = [ pwp for pwp in self.positional_word_parts if pwp.left + pwp.width < split_position ] transkription_positions += TranskriptionPosition.CREATE_TRANSKRIPTION_POSITION_LIST_FROM_PWPS(left_pwp, transkription_position_id=self.id) if second_split == -1: right_pwp = [ pwp for pwp in self.positional_word_parts if pwp not in left_pwp ] next_id = int(self.id) + 1 transkription_positions += TranskriptionPosition.CREATE_TRANSKRIPTION_POSITION_LIST_FROM_PWPS(right_pwp, transkription_position_id=str(next_id)) else: middle_pwp = [ pwp for pwp in self.positional_word_parts if pwp not in left_pwp and pwp.left + pwp.width < second_split ] next_id = int(self.id) + 1 transkription_positions += TranskriptionPosition.CREATE_TRANSKRIPTION_POSITION_LIST_FROM_PWPS(middle_pwp, transkription_position_id=str(next_id)) right_pwp = [ pwp for pwp in self.positional_word_parts if pwp not in left_pwp and pwp not in middle_pwp ] next_id = int(self.id) + 1 transkription_positions += TranskriptionPosition.CREATE_TRANSKRIPTION_POSITION_LIST_FROM_PWPS(right_pwp, transkription_position_id=str(next_id)) return transkription_positions def update_positional_word_parts(self, positional_word_parts): """Update positional_word_parts. """ if len(self.positional_word_parts) > 0 and self.positional_word_parts in self.attachable_objects: self.attachable_objects.remove(self.positional_word_parts) self.positional_word_parts = positional_word_parts self.attachable_objects += self.positional_word_parts @staticmethod def CREATE_TRANSKRIPTION_POSITION_LIST_FROM_PWPS(positional_word_parts, debug_message=None, debug_msg_string=None, transkription_position_id=0): """Creates a list of TranskriptionPosition from a list of (datatypes.positional_word_part) PositionalWordPart. [:return:] a list of (datatypes.transkription_position) TranskriptionPosition """ TOPCORRECTION = 1 debug_message = DebugMessage(message=debug_msg_string)\ if debug_msg_string is not None else debug_message transkription_positions = [] if len(positional_word_parts) < 1: return [] matrix = positional_word_parts[0].transform index = 0 matrices_differ = False style_class = positional_word_parts[0].style_class styles_differ = False while index < len(positional_word_parts) and not matrices_differ and not styles_differ: if Matrix.DO_CONVERSION_FACTORS_DIFFER(matrix, positional_word_parts[index].transform): matrices_differ = True elif style_class != positional_word_parts[index].style_class: styles_differ = True else: index += 1 if (matrices_differ or styles_differ) and index < len(positional_word_parts): debug_msg_string = 'matrices differ' if matrices_differ else 'styles differ' transkription_positions += TranskriptionPosition.CREATE_TRANSKRIPTION_POSITION_LIST_FROM_PWPS(\ positional_word_parts[index:], debug_msg_string=debug_msg_string, transkription_position_id=int(transkription_position_id)+1) positional_word_parts = positional_word_parts[:index] height = [ pwp.height for pwp in sorted(positional_word_parts, key=lambda pwp: pwp.height, reverse=True)][0] + 2*TOPCORRECTION x = positional_word_parts[0].left - TranskriptionPosition.ADD2X y = [ pwp.top for pwp in sorted(positional_word_parts, key=lambda pwp: pwp.top)][0] - TOPCORRECTION width = positional_word_parts[len(positional_word_parts)-1].left - x\ + positional_word_parts[len(positional_word_parts)-1].width + TranskriptionPosition.ADD2X for pwp_index, pwp in enumerate(positional_word_parts): pwp.id = pwp_index transkription_positions.insert(0, TranskriptionPosition(id=transkription_position_id, height=height, width=width, x=x, y=y, matrix=matrix,\ positional_word_parts=positional_word_parts, debug_message=debug_message)) return transkription_positions @staticmethod def CREATE_TRANSKRIPTION_POSITION_LIST(page, word_part_objs, matrix=None, debug_msg_string=None, transkription_field=None): """Creates a list of TranskriptionPosition from word_part_objs (i.e. a list of dictionaries with the keys: text, x, y, matrix, class). [:return:] a list of (datatypes.transkription_position) TranskriptionPosition """ positional_word_parts = [] debug_message = DebugMessage(message=debug_msg_string)\ if debug_msg_string is not None else None if page.svg_file is not None and isfile(page.svg_file): svg_path_tree = ET.parse(page.svg_file) namespaces = { k if k is not None else 'ns': v for k, v in svg_path_tree.getroot().nsmap.items() } xmin = 0.0 ymin = 0.0 if transkription_field is not None: xmin = transkription_field.xmin ymin = transkription_field.ymin for part_obj in word_part_objs: positional_word_parts += PositionalWordPart.CREATE_POSITIONAL_WORD_PART_LIST(\ part_obj, svg_path_tree, namespaces, page, start_id=len(positional_word_parts),\ xmin=xmin, ymin=ymin) else: positional_word_parts = PositionalWordPart.CREATE_SIMPLE_POSITIONAL_WORD_PART_LIST(page, word_part_objs) if len(positional_word_parts) > 0: return TranskriptionPosition.CREATE_TRANSKRIPTION_POSITION_LIST_FROM_PWPS(positional_word_parts, debug_message=debug_message) else: return [ TranskriptionPosition(matrix=matrix, debug_message=debug_message) ] Index: tests_svgscripts/test_data/N_VII_1_page006.xml =================================================================== --- tests_svgscripts/test_data/N_VII_1_page006.xml (revision 68) +++ tests_svgscripts/test_data/N_VII_1_page006.xml (revision 69) @@ -1,1275 +1,1275 @@ <?xml version="1.0" encoding="utf-8"?> <page number="6" orientation="North" source="tests_svgscripts/test_data/N_VII_1_xp5_4_page6.svg" status="OK" title="N VII 1" transkription-field-only="true"> <pdf file="/home/knister0/ownCloud/myNietzscheDE/KGW-IX_1-10online/N_VII_1//N_VII_1_xp5_4_page6.pdf"/> <svg file="./svg/N_VII_1_page006_web.svg" height="481.891" width="297.637"/> <style letterspacing-list="st7 st14"> <class clip-path="url(#SVGID_2_)" name="st0"/> <class clip-path="url(#SVGID_4_)" name="st1"/> <class font-family="Frutiger-LightItalic" name="st2"/> <class font-size="6px" name="st3"/> <class font-family="Frutiger-Light" name="st4"/> <class font-family="Frutiger-Bold" name="st5"/> <class font-size="9px" name="st6"/> <class letter-spacing="77" name="st7"/> <class clip-path="url(#SVGID_4_)" fill="#F8F9F8" name="st8"/> <class font-family="Weidemann-Book" name="st9"/> <class font-size="10px" name="st10"/> <class font-family="NewsGothicBT-Roman" name="st11"/> <class font-size="9.8px" name="st12"/> <class font-family="Frutiger-Europeen" name="st13"/> <class letter-spacing="1" name="st14"/> <class font-size="5px" name="st15"/> <class clip-path="url(#SVGID_4_)" fill="none" name="st16" stroke="#000000" stroke-miterlimit="10" stroke-width="0.4"/> </style> <line-number bottom="-1.0" id="1" top="0"/> <line-number bottom="23.6" id="2" top="0.0"/> <line-number bottom="25.6" id="3" top="24.6"/> <line-number bottom="47.2" id="4" top="26.6"/> <line-number bottom="49.2" id="5" top="48.2"/> <line-number bottom="70.8" id="6" top="50.2"/> <line-number bottom="72.8" id="7" top="71.8"/> <line-number bottom="94.4" id="8" top="73.8"/> <line-number bottom="96.4" id="9" top="95.4"/> <line-number bottom="118.0" id="10" top="97.4"/> <line-number bottom="120.0" id="11" top="119.0"/> <line-number bottom="141.6" id="12" top="121.0"/> <line-number bottom="143.601" id="13" top="142.6"/> <line-number bottom="165.2" id="14" top="144.601"/> <line-number bottom="167.2" id="15" top="166.2"/> <line-number bottom="188.8" id="16" top="168.2"/> <line-number bottom="190.8" id="17" top="189.8"/> <line-number bottom="212.4" id="18" top="191.8"/> <line-number bottom="214.4" id="19" top="213.4"/> <line-number bottom="236.0" id="20" top="215.4"/> <line-number bottom="238.0" id="21" top="237.0"/> <line-number bottom="259.6" id="22" top="239.0"/> <line-number bottom="261.601" id="23" top="260.6"/> <line-number bottom="283.2" id="24" top="262.601"/> <line-number bottom="285.2" id="25" top="284.2"/> <line-number bottom="306.8" id="26" top="286.2"/> <line-number bottom="308.8" id="27" top="307.8"/> <line-number bottom="330.4" id="28" top="309.8"/> <line-number bottom="332.401" id="29" top="331.4"/> <line-number bottom="354.0" id="30" top="333.401"/> <line-number bottom="356.0" id="31" top="355.0"/> <line-number bottom="377.6" id="32" top="357.0"/> <line-number bottom="379.6" id="33" top="378.6"/> <line-number bottom="401.201" id="34" top="380.6"/> <line-number bottom="403.201" id="35" top="402.201"/> <line-number bottom="424.8" id="36" top="404.201"/> <line-number bottom="426.8" id="37" top="425.8"/> <line-number bottom="448.4" id="38" top="427.8"/> <line-number bottom="450.401" id="39" top="449.4"/> <line-number bottom="472.0" id="40" top="451.401"/> <line-number bottom="531.811" id="41" top="473.0"/> <writing-process description="first version" version="0"/> <writing-process description="insertion and addition" version="1"/> <writing-process description="later insertion and addition" version="2"/> <word deleted="false" id="0" line-number="2" text="Ich"> <transkription-position bottom="25.475" height="11.11" id="0" left="36.701" top="14.365" width="12.719" writing-process-id="0"> <word-part bottom="23.6" height="7.125" id="0" left="36.851" style-class="st9 st10" symbol-id="glyph4-1" text="I" top="16.475" width="2.172"/> <word-part bottom="23.6" height="5.234" id="1" left="39.965" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="18.366" width="3.531"/> <word-part bottom="23.6" height="7.125" id="2" left="44.379" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="16.475" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="1" line-number="2" text="stehe"> <transkription-position bottom="25.475" height="11.11" id="0" left="52.727" top="14.365" width="20.739" writing-process-id="0"> <word-part bottom="23.6" height="5.234" id="0" left="52.877" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="18.366" width="2.938"/> <word-part bottom="23.6" height="6.422" id="1" left="56.551" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="17.178" width="2.781"/> <word-part bottom="23.6" height="5.234" id="2" left="59.665" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="18.366" width="3.703"/> <word-part bottom="23.6" height="7.125" id="3" left="64.259" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="16.475" width="4.891"/> <word-part bottom="23.6" height="5.234" id="4" left="69.613" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="18.366" width="3.703"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="2" line-number="2" text="anders"> <transkription-position bottom="25.397" height="11.11" id="0" left="77.201" top="14.287" width="26.238" writing-process-id="0"> <word-part bottom="23.6" height="5.234" id="0" left="77.351" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="18.366" width="3.812"/> <word-part bottom="23.6" height="5.312" id="1" left="81.765" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="18.288" width="4.891"/> <word-part bottom="23.6" height="7.203" id="2" left="87.119" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="16.397" width="4.281"/> <word-part bottom="23.6" height="5.234" id="3" left="92.273" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="18.366" width="3.703"/> <word-part bottom="23.6" height="5.312" id="4" left="96.867" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="18.288" width="2.984"/> <word-part bottom="23.6" height="5.234" id="5" left="100.351" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="18.366" width="2.938"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="3" line-number="2" text="zur"> <transkription-position bottom="27.288" height="11.11" id="0" left="107.019" top="16.178" width="13.232" writing-process-id="0"> <word-part bottom="23.6" height="5.062" id="0" left="107.169" style-class="st9 st10" symbol-id="glyph4-12" text="z" top="18.538" width="4.125"/> <word-part bottom="23.6" height="5.234" id="1" left="111.763" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="18.366" width="4.859"/> <word-part bottom="23.6" height="5.312" id="2" left="117.117" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="18.288" width="2.984"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="4" line-number="2" text="Unwissenheit"> <transkription-position bottom="25.35" height="11.11" id="0" left="123.595" top="14.24" width="55.175" writing-process-id="0"> <word-part bottom="23.6" height="7.25" id="0" left="123.745" style-class="st9 st10" symbol-id="glyph4-14" text="U" top="16.35" width="6.234"/> <word-part bottom="23.6" height="5.312" id="1" left="130.569" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="18.288" width="4.891"/> <word-part bottom="23.6" height="5.125" id="2" left="135.923" style-class="st9 st10" symbol-id="glyph4-15" text="w" top="18.475" width="7.562"/> <word-part bottom="23.6" height="6.844" id="3" left="143.487" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="16.757" width="2.094"/> <word-part bottom="23.6" height="5.234" id="4" left="146.041" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="18.366" width="2.938"/> <word-part bottom="23.6" height="5.234" id="5" left="149.715" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="18.366" width="2.938"/> <word-part bottom="23.6" height="5.234" id="6" left="153.389" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="18.366" width="3.703"/> <word-part bottom="23.6" height="5.312" id="7" left="157.983" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="18.288" width="4.891"/> <word-part bottom="23.6" height="7.125" id="8" left="163.337" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="16.475" width="4.891"/> <word-part bottom="23.6" height="5.234" id="9" left="168.691" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="18.366" width="3.703"/> <word-part bottom="23.6" height="6.844" id="10" left="173.285" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="16.757" width="2.094"/> <word-part bottom="23.6" height="6.422" id="11" left="175.839" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="17.178" width="2.781"/> <debug id="0" message="check for line breaks, diffx: 155.865, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="5" line-number="4" text="u"> <transkription-position bottom="50.966" height="11.11" id="0" left="19.693" top="39.856" width="5.159" writing-process-id="0"> <word-part bottom="47.2" height="5.234" id="0" left="19.843" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="41.966" width="4.859"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="6" line-number="4" text="Ungewißheit."> <transkription-position bottom="48.888" height="11.11" id="0" left="28.191" top="37.778" width="53.788" writing-process-id="0"> <word-part bottom="47.2" height="7.25" id="0" left="28.341" style-class="st9 st10" symbol-id="glyph4-14" text="U" top="39.95" width="6.234"/> <word-part bottom="47.2" height="5.312" id="1" left="35.165" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="41.888" width="4.891"/> <word-part bottom="47.2" height="7.281" id="2" left="40.519" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="39.919" width="4.203"/> <word-part bottom="47.2" height="5.234" id="3" left="45.113" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="41.966" width="3.703"/> <word-part bottom="47.2" height="5.125" id="4" left="49.707" style-class="st9 st10" symbol-id="glyph4-15" text="w" top="42.075" width="7.562"/> <word-part bottom="47.2" height="6.844" id="5" left="57.271" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="40.357" width="2.094"/> <word-part bottom="47.2" height="7.312" id="6" left="59.825" style-class="st9 st10" symbol-id="glyph4-18" text="ß" top="39.888" width="4.516"/> <word-part bottom="47.2" height="7.125" id="7" left="64.979" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="40.075" width="4.891"/> <word-part bottom="47.2" height="5.234" id="8" left="70.333" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="41.966" width="3.703"/> <word-part bottom="47.2" height="6.844" id="9" left="74.927" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="40.357" width="2.094"/> <word-part bottom="47.2" height="6.422" id="10" left="77.481" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="40.778" width="2.781"/> <word-part bottom="47.2" height="1.25" id="11" left="80.595" style-class="st9 st10" symbol-id="glyph4-19" text="." top="45.95" width="1.234"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="7" line-number="4" text="Nicht,"> <transkription-position bottom="49.075" height="11.11" id="0" left="86.343" top="37.965" width="24.368" writing-process-id="0"> <word-part bottom="47.2" height="7.125" id="0" left="86.493" style-class="st9 st10" symbol-id="glyph4-20" text="N" top="40.075" width="6.453"/> <word-part bottom="47.2" height="6.844" id="1" left="93.687" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="40.357" width="2.094"/> <word-part bottom="47.2" height="5.234" id="2" left="96.241" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="41.966" width="3.531"/> <word-part bottom="47.2" height="7.125" id="3" left="100.655" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="40.075" width="4.891"/> <word-part bottom="47.2" height="6.422" id="4" left="106.009" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="40.778" width="2.781"/> <word-part bottom="47.2" height="3.234" id="5" left="109.123" style-class="st9 st10" symbol-id="glyph4-21" text="," top="43.966" width="1.438"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="8" line-number="4" text="daß"> <transkription-position bottom="48.888" height="11.11" id="0" left="114.871" top="37.778" width="14.384" writing-process-id="0"> <word-part bottom="47.2" height="7.203" id="0" left="115.021" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="39.997" width="4.281"/> <word-part bottom="47.2" height="5.234" id="1" left="120.175" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="41.966" width="3.812"/> <word-part bottom="47.2" height="7.312" id="2" left="124.589" style-class="st9 st10" symbol-id="glyph4-18" text="ß" top="39.888" width="4.516"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="9" line-number="4" text="etwas"> <transkription-position bottom="49.778" height="11.11" id="0" left="132.737" top="38.668" width="22.924" writing-process-id="0"> <word-part bottom="47.2" height="5.234" id="0" left="132.887" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="41.966" width="3.703"/> <word-part bottom="47.2" height="6.422" id="1" left="137.481" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="40.778" width="2.781"/> <word-part bottom="47.2" height="5.125" id="2" left="140.595" style-class="st9 st10" symbol-id="glyph4-15" text="w" top="42.075" width="7.562"/> <word-part bottom="47.2" height="5.234" id="3" left="148.159" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="41.966" width="3.812"/> <word-part bottom="47.2" height="5.234" id="4" left="152.573" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="41.966" width="2.938"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="10" line-number="4" text="unerkannt"> <transkription-position bottom="49.075" height="11.11" id="0" left="159.241" top="37.965" width="41.953" writing-process-id="0"> <word-part bottom="47.2" height="5.234" id="0" left="159.391" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="41.966" width="4.859"/> <word-part bottom="47.2" height="5.312" id="1" left="164.745" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="41.888" width="4.891"/> <word-part bottom="47.2" height="5.234" id="2" left="170.099" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="41.966" width="3.703"/> <word-part bottom="47.2" height="5.312" id="3" left="174.693" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="41.888" width="2.984"/> <word-part bottom="47.2" height="7.125" id="4" left="178.177" style-class="st9 st10" symbol-id="glyph4-22" text="k" top="40.075" width="4.781"/> <word-part bottom="47.2" height="5.234" id="5" left="183.141" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="41.966" width="3.812"/> <word-part bottom="47.2" height="5.312" id="6" left="187.555" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="41.888" width="4.891"/> <word-part bottom="47.2" height="5.312" id="7" left="192.909" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="41.888" width="4.891"/> <word-part bottom="47.2" height="6.422" id="8" left="198.263" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="40.778" width="2.781"/> <debug id="0" message="check for line breaks, diffx: 178.257, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="11" line-number="6" text="bleibt,"> <transkription-position bottom="72.597" height="11.11" id="0" left="19.693" top="61.487" width="24.482" writing-process-id="0"> <word-part bottom="70.8" height="7.203" id="0" left="19.843" style-class="st9 st10" symbol-id="glyph4-23" text="b" top="63.597" width="4.281"/> <word-part bottom="70.8" height="7.125" id="1" left="24.807" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="63.675" width="2.094"/> <word-part bottom="70.8" height="5.234" id="2" left="27.361" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="65.566" width="3.703"/> <word-part bottom="70.8" height="6.844" id="3" left="31.955" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="63.957" width="2.094"/> <word-part bottom="70.8" height="7.203" id="4" left="34.509" style-class="st9 st10" symbol-id="glyph4-23" text="b" top="63.597" width="4.281"/> <word-part bottom="70.8" height="6.422" id="5" left="39.473" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="64.378" width="2.781"/> <word-part bottom="70.8" height="3.234" id="6" left="42.587" style-class="st9 st10" symbol-id="glyph4-21" text="," top="67.566" width="1.438"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="12" line-number="6" text="ist"> <transkription-position bottom="72.957" height="11.11" id="0" left="48.335" top="61.847" width="9.309" writing-process-id="0"> <word-part bottom="70.8" height="6.844" id="0" left="48.485" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="63.957" width="2.094"/> <word-part bottom="70.8" height="5.234" id="1" left="51.039" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="65.566" width="2.938"/> <word-part bottom="70.8" height="6.422" id="2" left="54.713" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="64.378" width="2.781"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="13" line-number="6" text="mein"> <transkription-position bottom="72.957" height="11.11" id="0" left="60.821" top="61.847" width="20.273" writing-process-id="0"> <word-part bottom="70.8" height="5.312" id="0" left="60.971" style-class="st9 st10" symbol-id="glyph4-25" text="m" top="65.488" width="7.375"/> <word-part bottom="70.8" height="5.234" id="1" left="68.905" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="65.566" width="3.703"/> <word-part bottom="70.8" height="6.844" id="2" left="73.499" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="63.957" width="2.094"/> <word-part bottom="70.8" height="5.312" id="3" left="76.053" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="65.488" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="14" line-number="6" text="Kummer;"> <transkription-position bottom="72.675" height="11.11" id="0" left="84.401" top="61.565" width="37.122" writing-process-id="0"> <word-part bottom="70.8" height="7.125" id="0" left="84.551" style-class="st9 st10" symbol-id="glyph4-26" text="K" top="63.675" width="5.422"/> <word-part bottom="70.8" height="5.234" id="1" left="90.635" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="65.566" width="4.859"/> <word-part bottom="70.8" height="5.312" id="2" left="95.989" style-class="st9 st10" symbol-id="glyph4-25" text="m" top="65.488" width="7.375"/> <word-part bottom="70.8" height="5.312" id="3" left="103.923" style-class="st9 st10" symbol-id="glyph4-25" text="m" top="65.488" width="7.375"/> <word-part bottom="70.8" height="5.234" id="4" left="111.857" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="65.566" width="3.703"/> <word-part bottom="70.8" height="5.312" id="5" left="116.451" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="65.488" width="2.984"/> <word-part bottom="70.8" height="6.656" id="6" left="119.935" style-class="st9 st10" symbol-id="glyph4-27" text=";" top="64.144" width="1.438"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="15" line-number="6" text="ich"> <transkription-position bottom="72.675" height="11.11" id="0" left="125.683" top="61.565" width="12.159" writing-process-id="0"> <word-part bottom="70.8" height="6.844" id="0" left="125.833" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="63.957" width="2.094"/> <word-part bottom="70.8" height="5.234" id="1" left="128.387" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="65.566" width="3.531"/> <word-part bottom="70.8" height="7.125" id="2" left="132.801" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="63.675" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="16" line-number="6" text="freue"> <transkription-position bottom="72.675" height="11.11" id="0" left="141.149" top="61.565" width="20.188" writing-process-id="0"> <word-part bottom="70.8" height="7.125" id="0" left="141.299" style-class="st9 st10" symbol-id="glyph4-28" text="f" top="63.675" width="2.766"/> <word-part bottom="70.8" height="5.312" id="1" left="144.043" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="65.488" width="2.984"/> <word-part bottom="70.8" height="5.234" id="2" left="147.536" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="65.566" width="3.703"/> <word-part bottom="70.8" height="5.234" id="3" left="152.13" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="65.566" width="4.859"/> <word-part bottom="70.8" height="5.234" id="4" left="157.484" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="65.566" width="3.703"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="17" line-number="6" text="mich,"> <transkription-position bottom="72.675" height="11.11" id="0" left="165.072" top="61.565" width="21.995" writing-process-id="0"> <word-part bottom="70.8" height="5.312" id="0" left="165.222" style-class="st9 st10" symbol-id="glyph4-25" text="m" top="65.488" width="7.375"/> <word-part bottom="70.8" height="6.844" id="1" left="173.156" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="63.957" width="2.094"/> <word-part bottom="70.8" height="5.234" id="2" left="175.71" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="65.566" width="3.531"/> <word-part bottom="70.8" height="7.125" id="3" left="180.124" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="63.675" width="4.891"/> <word-part bottom="70.8" height="3.234" id="4" left="185.479" style-class="st9 st10" symbol-id="glyph4-21" text="," top="67.566" width="1.438"/> <debug id="0" message="check for line breaks, diffx: 165.636, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="18" line-number="8" text="daß"> <transkription-position bottom="96.088" height="11.11" id="0" left="19.693" top="84.978" width="14.384" writing-process-id="0"> <word-part bottom="94.4" height="7.203" id="0" left="19.843" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="87.197" width="4.281"/> <word-part bottom="94.4" height="5.234" id="1" left="24.997" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="89.166" width="3.812"/> <word-part bottom="94.4" height="7.312" id="2" left="29.411" style-class="st9 st10" symbol-id="glyph4-18" text="ß" top="87.088" width="4.516"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="19" line-number="8" text="es"> <transkription-position bottom="98.166" height="11.11" id="0" left="37.559" top="87.056" width="7.832" writing-process-id="0"> <word-part bottom="94.4" height="5.234" id="0" left="37.709" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="89.166" width="3.703"/> <word-part bottom="94.4" height="5.234" id="1" left="42.303" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="89.166" width="2.938"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="20" line-number="8" text="vielmehr"> <transkription-position bottom="96.275" height="11.11" id="0" left="48.971" top="85.165" width="35.662" writing-process-id="0"> <word-part bottom="94.4" height="5.125" id="0" left="49.121" style-class="st9 st10" symbol-id="glyph4-29" text="v" top="89.275" width="4.797"/> <word-part bottom="94.4" height="6.844" id="1" left="53.915" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="87.557" width="2.094"/> <word-part bottom="94.4" height="5.234" id="2" left="56.469" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="89.166" width="3.703"/> <word-part bottom="94.4" height="7.125" id="3" left="61.063" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="87.275" width="2.094"/> <word-part bottom="94.4" height="5.312" id="4" left="63.617" style-class="st9 st10" symbol-id="glyph4-25" text="m" top="89.088" width="7.375"/> <word-part bottom="94.4" height="5.234" id="5" left="71.551" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="89.166" width="3.703"/> <word-part bottom="94.4" height="7.125" id="6" left="76.145" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="87.275" width="4.891"/> <word-part bottom="94.4" height="5.312" id="7" left="81.499" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="89.088" width="2.984"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="21" line-number="8" text="eine"> <transkription-position bottom="96.557" height="11.11" id="0" left="87.977" top="85.447" width="16.505" writing-process-id="0"> <word-part bottom="94.4" height="5.234" id="0" left="88.127" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="89.166" width="3.703"/> <word-part bottom="94.4" height="6.844" id="1" left="92.721" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="87.557" width="2.094"/> <word-part bottom="94.4" height="5.312" id="2" left="95.275" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="89.088" width="4.891"/> <word-part bottom="94.4" height="5.234" id="3" left="100.629" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="89.166" width="3.703"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="22" line-number="8" text="Art"> <transkription-position bottom="96.275" height="11.11" id="0" left="108.217" top="85.165" width="12.829" writing-process-id="0"> <word-part bottom="94.4" height="7.125" id="0" left="108.367" style-class="st9 st10" symbol-id="glyph4-30" text="A" top="87.275" width="6.359"/> <word-part bottom="94.4" height="5.312" id="1" left="114.631" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="89.088" width="2.984"/> <word-part bottom="94.4" height="6.422" id="2" left="118.115" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="87.978" width="2.781"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="23" line-number="8" text="von"> <transkription-position bottom="98.088" height="11.11" id="0" left="124.223" top="86.978" width="14.949" writing-process-id="0"> <word-part bottom="94.4" height="5.125" id="0" left="124.373" style-class="st9 st10" symbol-id="glyph4-29" text="v" top="89.275" width="4.797"/> <word-part bottom="94.4" height="5.234" id="1" left="129.167" style-class="st9 st10" symbol-id="glyph4-31" text="o" top="89.166" width="4.062"/> <word-part bottom="94.4" height="5.312" id="2" left="134.131" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="89.088" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="24" line-number="8" text="Erkenntniß"> <transkription-position bottom="96.088" height="11.11" id="0" left="142.479" top="84.978" width="45.112" writing-process-id="0"> <word-part bottom="94.4" height="7.125" id="0" left="142.629" style-class="st9 st10" symbol-id="glyph4-32" text="E" top="87.275" width="4.547"/> <word-part bottom="94.4" height="5.312" id="1" left="148.153" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="89.088" width="2.984"/> <word-part bottom="94.4" height="7.125" id="2" left="151.637" style-class="st9 st10" symbol-id="glyph4-22" text="k" top="87.275" width="4.781"/> <word-part bottom="94.4" height="5.234" id="3" left="156.601" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="89.166" width="3.703"/> <word-part bottom="94.4" height="5.312" id="4" left="161.195" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="89.088" width="4.891"/> <word-part bottom="94.4" height="5.312" id="5" left="166.549" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="89.088" width="4.891"/> <word-part bottom="94.4" height="6.422" id="6" left="171.903" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="87.978" width="2.781"/> <word-part bottom="94.4" height="5.312" id="7" left="175.017" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="89.088" width="4.891"/> <word-part bottom="94.4" height="6.844" id="8" left="180.371" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="87.557" width="2.094"/> <word-part bottom="94.4" height="7.312" id="9" left="182.925" style-class="st9 st10" symbol-id="glyph4-18" text="ß" top="87.088" width="4.516"/> <debug id="0" message="check for line breaks, diffx: 162.926, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="25" line-number="10" text="geben"> <transkription-position bottom="119.719" height="11.11" id="0" left="19.693" top="108.609" width="23.937" writing-process-id="0"> <word-part bottom="118.0" height="7.281" id="0" left="19.843" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="110.719" width="4.203"/> <word-part bottom="118.0" height="5.234" id="1" left="24.437" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="112.766" width="3.703"/> <word-part bottom="118.0" height="7.203" id="2" left="29.031" style-class="st9 st10" symbol-id="glyph4-23" text="b" top="110.797" width="4.281"/> <word-part bottom="118.0" height="5.234" id="3" left="33.995" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="112.766" width="3.703"/> <word-part bottom="118.0" height="5.312" id="4" left="38.589" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="112.688" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="26" line-number="10" text="kann"> <transkription-position bottom="119.875" height="11.11" id="0" left="46.939" top="108.765" width="19.923" writing-process-id="0"> <word-part bottom="118.0" height="7.125" id="0" left="47.089" style-class="st9 st10" symbol-id="glyph4-22" text="k" top="110.875" width="4.781"/> <word-part bottom="118.0" height="5.234" id="1" left="52.053" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="112.766" width="3.812"/> <word-part bottom="118.0" height="5.312" id="2" left="56.467" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="112.688" width="4.891"/> <word-part bottom="118.0" height="5.312" id="3" left="61.821" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="112.688" width="4.891"/> <debug id="0" message="check for line breaks, diffx: 8.537, diffy: 0.0, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="27" line-number="10" text="u."> <transkription-position bottom="121.766" height="11.11" id="0" left="70.168" top="110.656" width="6.888" writing-process-id="0"> <word-part bottom="118.0" height="5.234" id="0" left="70.318" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="112.766" width="4.859"/> <word-part bottom="118.0" height="1.25" id="1" left="75.672" style-class="st9 st10" symbol-id="glyph4-19" text="." top="116.75" width="1.234"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="28" line-number="10" text="bewundere"> <transkription-position bottom="119.797" height="11.11" id="0" left="81.419" top="108.687" width="45.065" writing-process-id="0"> <word-part bottom="118.0" height="7.203" id="0" left="81.569" style-class="st9 st10" symbol-id="glyph4-23" text="b" top="110.797" width="4.281"/> <word-part bottom="118.0" height="5.234" id="1" left="86.533" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="112.766" width="3.703"/> <word-part bottom="118.0" height="5.125" id="2" left="91.127" style-class="st9 st10" symbol-id="glyph4-15" text="w" top="112.875" width="7.562"/> <word-part bottom="118.0" height="5.234" id="3" left="98.691" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="112.766" width="4.859"/> <word-part bottom="118.0" height="5.312" id="4" left="104.045" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="112.688" width="4.891"/> <word-part bottom="118.0" height="7.203" id="5" left="109.399" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="110.797" width="4.281"/> <word-part bottom="118.0" height="5.234" id="6" left="114.553" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="112.766" width="3.703"/> <word-part bottom="118.0" height="5.312" id="7" left="119.147" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="112.688" width="2.984"/> <word-part bottom="118.0" height="5.234" id="8" left="122.631" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="112.766" width="3.703"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="29" line-number="10" text="die"> <transkription-position bottom="119.797" height="11.11" id="0" left="130.218" top="108.687" width="11.711" writing-process-id="0"> <word-part bottom="118.0" height="7.203" id="0" left="130.368" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="110.797" width="4.281"/> <word-part bottom="118.0" height="6.844" id="1" left="135.522" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="111.157" width="2.094"/> <word-part bottom="118.0" height="5.234" id="2" left="138.076" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="112.766" width="3.703"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="30" line-number="10" text="Complicirtheit"> <transkription-position bottom="119.641" height="11.11" id="0" left="145.663" top="108.531" width="58.753" writing-process-id="0"> <word-part bottom="118.0" height="7.359" id="0" left="145.813" style-class="st9 st10" symbol-id="glyph4-33" text="C" top="110.641" width="5.328"/> <word-part bottom="118.0" height="5.234" id="1" left="152.447" style-class="st9 st10" symbol-id="glyph4-31" text="o" top="112.766" width="4.062"/> <word-part bottom="118.0" height="5.312" id="2" left="157.411" style-class="st9 st10" symbol-id="glyph4-25" text="m" top="112.688" width="7.375"/> <word-part bottom="118.0" height="7.188" id="3" left="165.345" style-class="st9 st10" symbol-id="glyph4-34" text="p" top="110.813" width="4.284"/> <word-part bottom="118.0" height="7.125" id="4" left="170.309" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="110.875" width="2.094"/> <word-part bottom="118.0" height="6.844" id="5" left="172.863" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="111.157" width="2.094"/> <word-part bottom="118.0" height="5.234" id="6" left="175.417" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="112.766" width="3.531"/> <word-part bottom="118.0" height="6.844" id="7" left="179.831" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="111.157" width="2.094"/> <word-part bottom="118.0" height="5.312" id="8" left="182.385" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="112.688" width="2.984"/> <word-part bottom="118.0" height="6.422" id="9" left="185.869" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="111.578" width="2.781"/> <word-part bottom="118.0" height="7.125" id="10" left="188.983" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="110.875" width="4.891"/> <word-part bottom="118.0" height="5.234" id="11" left="194.337" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="112.766" width="3.703"/> <word-part bottom="118.0" height="6.844" id="12" left="198.931" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="111.157" width="2.094"/> <word-part bottom="118.0" height="6.422" id="13" left="201.485" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="111.578" width="2.781"/> <debug id="0" message="check for line breaks, diffx: 181.522, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="31" line-number="12" text="dieses"> <transkription-position bottom="143.397" height="11.11" id="0" left="19.693" top="132.287" width="23.808" writing-process-id="0"> <word-part bottom="141.6" height="7.203" id="0" left="19.843" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="134.397" width="4.281"/> <word-part bottom="141.6" height="6.844" id="1" left="24.997" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="134.757" width="2.094"/> <word-part bottom="141.6" height="5.234" id="2" left="27.551" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="136.366" width="3.703"/> <word-part bottom="141.6" height="5.234" id="3" left="32.145" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="136.366" width="2.938"/> <word-part bottom="141.6" height="5.234" id="4" left="35.819" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="136.366" width="3.703"/> <word-part bottom="141.6" height="5.234" id="5" left="40.413" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="136.366" width="2.938"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="32" line-number="12" text="Ermöglichung."> <transkription-position bottom="143.319" height="11.11" id="0" left="47.081" top="132.209" width="58.212" writing-process-id="0"> <word-part bottom="141.6" height="7.125" id="0" left="47.231" style-class="st9 st10" symbol-id="glyph4-32" text="E" top="134.475" width="4.547"/> <word-part bottom="141.6" height="5.312" id="1" left="52.755" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="136.288" width="2.984"/> <word-part bottom="141.6" height="5.312" id="2" left="56.239" style-class="st9 st10" symbol-id="glyph4-25" text="m" top="136.288" width="7.375"/> <word-part bottom="141.6" height="6.859" id="3" left="64.173" style-class="st9 st10" symbol-id="glyph4-35" text="ö" top="134.741" width="4.062"/> <word-part bottom="141.6" height="7.281" id="4" left="69.137" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="134.319" width="4.203"/> <word-part bottom="141.6" height="7.125" id="5" left="73.731" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="134.475" width="2.094"/> <word-part bottom="141.6" height="6.844" id="6" left="76.285" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="134.757" width="2.094"/> <word-part bottom="141.6" height="5.234" id="7" left="78.839" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="136.366" width="3.531"/> <word-part bottom="141.6" height="7.125" id="8" left="83.253" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="134.475" width="4.891"/> <word-part bottom="141.6" height="5.234" id="9" left="88.607" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="136.366" width="4.859"/> <word-part bottom="141.6" height="5.312" id="10" left="93.961" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="136.288" width="4.891"/> <word-part bottom="141.6" height="7.281" id="11" left="99.315" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="134.319" width="4.203"/> <word-part bottom="141.6" height="1.25" id="12" left="103.909" style-class="st9 st10" symbol-id="glyph4-19" text="." top="140.35" width="1.234"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="33" line-number="12" text="Das"> <transkription-position bottom="143.475" height="11.11" id="0" left="109.657" top="132.365" width="14.666" writing-process-id="0"> <word-part bottom="141.6" height="7.125" id="0" left="109.807" style-class="st9 st10" symbol-id="glyph4-36" text="D" top="134.475" width="5.859"/> <word-part bottom="141.6" height="5.234" id="1" left="116.821" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="136.366" width="3.812"/> <word-part bottom="141.6" height="5.234" id="2" left="121.235" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="136.366" width="2.938"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="34" line-number="12" text="Mittel"> <transkription-position bottom="143.475" height="11.11" id="0" left="127.903" top="132.365" width="24.624" writing-process-id="0"> <word-part bottom="141.6" height="7.125" id="0" left="128.053" style-class="st9 st10" symbol-id="glyph4-37" text="M" top="134.475" width="8.562"/> <word-part bottom="141.6" height="6.844" id="1" left="136.907" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="134.757" width="2.094"/> <word-part bottom="141.6" height="6.422" id="2" left="139.461" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="135.178" width="2.781"/> <word-part bottom="141.6" height="6.422" id="3" left="142.575" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="135.178" width="2.781"/> <word-part bottom="141.6" height="5.234" id="4" left="145.689" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="136.366" width="3.703"/> <word-part bottom="141.6" height="7.125" id="5" left="150.283" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="134.475" width="2.094"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="35" line-number="12" text="ist:"> <transkription-position bottom="143.757" height="11.11" id="0" left="155.831" top="132.647" width="10.876" writing-process-id="0"> <word-part bottom="141.6" height="6.844" id="0" left="155.981" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="134.757" width="2.094"/> <word-part bottom="141.6" height="5.234" id="1" left="158.535" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="136.366" width="2.938"/> <word-part bottom="141.6" height="6.422" id="2" left="162.209" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="135.178" width="2.781"/> <word-part bottom="141.6" height="4.75" id="3" left="165.323" style-class="st9 st10" symbol-id="glyph4-38" text=":" top="136.85" width="1.234"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="36" line-number="12" text="die"> <transkription-position bottom="143.397" height="11.11" id="0" left="171.071" top="132.287" width="11.711" writing-process-id="0"> <word-part bottom="141.6" height="7.203" id="0" left="171.221" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="134.397" width="4.281"/> <word-part bottom="141.6" height="6.844" id="1" left="176.375" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="134.757" width="2.094"/> <word-part bottom="141.6" height="5.234" id="2" left="178.929" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="136.366" width="3.703"/> <debug id="0" message="check for line breaks, diffx: 158.927, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="37" line-number="14" text="Einführung"> <transkription-position bottom="166.919" height="11.11" id="0" left="19.693" top="155.809" width="45.579" writing-process-id="0"> <word-part bottom="165.2" height="7.125" id="0" left="19.843" style-class="st9 st10" symbol-id="glyph4-32" text="E" top="158.075" width="4.547"/> <word-part bottom="165.2" height="6.844" id="1" left="25.367" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="158.357" width="2.094"/> <word-part bottom="165.2" height="5.312" id="2" left="27.921" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="159.888" width="4.891"/> <word-part bottom="165.2" height="7.125" id="3" left="33.275" style-class="st9 st10" symbol-id="glyph4-28" text="f" top="158.075" width="2.766"/> <word-part bottom="165.2" height="6.859" id="4" left="36.019" style-class="st9 st10" symbol-id="glyph4-39" text="ü" top="158.341" width="4.859"/> <word-part bottom="165.2" height="7.125" id="5" left="41.373" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="158.075" width="4.891"/> <word-part bottom="165.2" height="5.312" id="6" left="46.727" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="159.888" width="2.984"/> <word-part bottom="165.2" height="5.234" id="7" left="50.211" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="159.966" width="4.859"/> <word-part bottom="165.2" height="5.312" id="8" left="55.565" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="159.888" width="4.891"/> <word-part bottom="165.2" height="7.281" id="9" left="60.919" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="157.919" width="4.203"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="38" line-number="14" text="vollständiger"> <transkription-position bottom="166.919" height="11.11" id="0" left="68.507" top="155.809" width="51.602" writing-process-id="0"> <word-part bottom="165.2" height="5.125" id="0" left="68.657" style-class="st9 st10" symbol-id="glyph4-29" text="v" top="160.075" width="4.797"/> <word-part bottom="165.2" height="5.234" id="1" left="73.451" style-class="st9 st10" symbol-id="glyph4-31" text="o" top="159.966" width="4.062"/> <word-part bottom="165.2" height="7.125" id="2" left="78.415" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="158.075" width="2.094"/> <word-part bottom="165.2" height="7.125" id="3" left="80.969" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="158.075" width="2.094"/> <word-part bottom="165.2" height="5.234" id="4" left="83.523" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="159.966" width="2.938"/> <word-part bottom="165.2" height="6.422" id="5" left="87.197" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="158.778" width="2.781"/> <word-part bottom="165.2" height="6.859" id="6" left="90.311" style-class="st9 st10" symbol-id="glyph4-40" text="ä" top="158.341" width="3.812"/> <word-part bottom="165.2" height="5.312" id="7" left="94.725" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="159.888" width="4.891"/> <word-part bottom="165.2" height="7.203" id="8" left="100.079" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="157.997" width="4.281"/> <word-part bottom="165.2" height="6.844" id="9" left="105.233" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="158.357" width="2.094"/> <word-part bottom="165.2" height="7.281" id="10" left="107.787" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="157.919" width="4.203"/> <word-part bottom="165.2" height="5.234" id="11" left="112.381" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="159.966" width="3.703"/> <word-part bottom="165.2" height="5.312" id="12" left="116.975" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="159.888" width="2.984"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="39" line-number="14" text="Fictionen"> <transkription-position bottom="166.902" height="10.892" id="0" left="123.462" top="156.01" width="37.818" writing-process-id="0"> <word-part bottom="165.2" height="7.078" id="0" left="123.612" style-class="st11 st12" symbol-id="glyph5-1" text="F" top="158.122" width="4.156"/> <word-part bottom="165.2" height="7.078" id="1" left="128.869" style-class="st11 st12" symbol-id="glyph5-2" text="i" top="158.122" width="0.844"/> <word-part bottom="165.2" height="5.312" id="2" left="131.474" style-class="st11 st12" symbol-id="glyph5-3" text="c" top="159.888" width="4.016"/> <word-part bottom="165.2" height="6.875" id="3" left="136.244" style-class="st11 st12" symbol-id="glyph5-4" text="t" top="158.325" width="2.688"/> <word-part bottom="165.2" height="7.078" id="4" left="139.418" style-class="st11 st12" symbol-id="glyph5-2" text="i" top="158.122" width="0.844"/> <word-part bottom="165.2" height="5.312" id="5" left="142.023" style-class="st11 st12" symbol-id="glyph5-5" text="o" top="159.888" width="4.281"/> <word-part bottom="165.2" height="5.219" id="6" left="147.126" style-class="st11 st12" symbol-id="glyph5-6" text="n" top="159.982" width="3.688"/> <word-part bottom="165.2" height="5.312" id="7" left="152.554" style-class="st11 st12" symbol-id="glyph5-7" text="e" top="159.888" width="4.109"/> <word-part bottom="165.2" height="5.219" id="8" left="157.442" style-class="st11 st12" symbol-id="glyph5-6" text="n" top="159.982" width="3.688"/> <debug id="0" message="check for line breaks, diffx: 8.624, diffy: 0.0, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="40" line-number="14" text="als"> <transkription-position bottom="167.075" height="11.11" id="0" left="165.867" top="155.965" width="10.206" writing-process-id="0"> <word-part bottom="165.2" height="5.234" id="0" left="166.017" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="159.966" width="3.812"/> <word-part bottom="165.2" height="7.125" id="1" left="170.431" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="158.075" width="2.094"/> <word-part bottom="165.2" height="5.234" id="2" left="172.985" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="159.966" width="2.938"/> <debug id="0" message="check for line breaks, diffx: 153.134, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="41" line-number="16" text="Schemata,"> <transkription-position bottom="190.252" height="10.892" id="0" left="19.693" top="179.36" width="41.68" writing-process-id="0"> <word-part bottom="188.8" height="7.328" id="0" left="19.843" style-class="st11 st12" symbol-id="glyph5-8" text="S" top="181.472" width="4.703"/> <word-part bottom="188.8" height="5.312" id="1" left="25.504" style-class="st11 st12" symbol-id="glyph5-3" text="c" top="183.488" width="4.016"/> <word-part bottom="188.8" height="7.078" id="2" left="30.274" style-class="st11 st12" symbol-id="glyph5-9" text="h" top="181.722" width="3.828"/> <word-part bottom="188.8" height="5.312" id="3" left="35.838" style-class="st11 st12" symbol-id="glyph5-7" text="e" top="183.488" width="4.109"/> <word-part bottom="188.8" height="5.219" id="4" left="40.725" style-class="st11 st12" symbol-id="glyph5-10" text="m" top="183.582" width="6.578"/> <word-part bottom="188.8" height="5.297" id="5" left="49.022" style-class="st11 st12" symbol-id="glyph5-11" text="a" top="183.503" width="3.906"/> <word-part bottom="188.8" height="6.875" id="6" left="54.145" style-class="st11 st12" symbol-id="glyph5-4" text="t" top="181.925" width="2.688"/> <word-part bottom="188.8" height="5.297" id="7" left="57.317" style-class="st11 st12" symbol-id="glyph5-11" text="a" top="183.503" width="3.906"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> <transkription-position bottom="194.566" height="11.11" id="1" left="62.294" top="183.456" width="1.738" writing-process-id="0"> <word-part bottom="188.8" height="3.234" id="0" left="62.444" style-class="st9 st10" symbol-id="glyph4-21" text="," top="185.566" width="1.438"/> <debug id="0" message="styles differ"/> </transkription-position> </word> <word deleted="false" id="42" line-number="16" text="nach"> <transkription-position bottom="190.675" height="11.11" id="0" left="68.192" top="179.565" width="19.373" writing-process-id="0"> <word-part bottom="188.8" height="5.312" id="0" left="68.342" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="183.488" width="4.891"/> <word-part bottom="188.8" height="5.234" id="1" left="73.696" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="183.566" width="3.812"/> <word-part bottom="188.8" height="5.234" id="2" left="78.11" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="183.566" width="3.531"/> <word-part bottom="188.8" height="7.125" id="3" left="82.524" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="181.675" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="43" line-number="16" text="denen"> <transkription-position bottom="190.597" height="11.11" id="0" left="90.872" top="179.487" width="24.887" writing-process-id="0"> <word-part bottom="188.8" height="7.203" id="0" left="91.022" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="181.597" width="4.281"/> <word-part bottom="188.8" height="5.234" id="1" left="96.176" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="183.566" width="3.703"/> <word-part bottom="188.8" height="5.312" id="2" left="100.77" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="183.488" width="4.891"/> <word-part bottom="188.8" height="5.234" id="3" left="106.124" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="183.566" width="3.703"/> <word-part bottom="188.8" height="5.312" id="4" left="110.718" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="183.488" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="44" line-number="16" text="wir"> <transkription-position bottom="190.957" height="11.11" id="0" left="119.066" top="179.847" width="13.402" writing-process-id="0"> <word-part bottom="188.8" height="5.125" id="0" left="119.216" style-class="st9 st10" symbol-id="glyph4-15" text="w" top="183.675" width="7.562"/> <word-part bottom="188.8" height="6.844" id="1" left="126.78" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="181.957" width="2.094"/> <word-part bottom="188.8" height="5.312" id="2" left="129.334" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="183.488" width="2.984"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="45" line-number="16" text="uns"> <transkription-position bottom="192.488" height="11.11" id="0" left="135.812" top="181.378" width="13.946" writing-process-id="0"> <word-part bottom="188.8" height="5.234" id="0" left="135.962" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="183.566" width="4.859"/> <word-part bottom="188.8" height="5.312" id="1" left="141.316" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="183.488" width="4.891"/> <word-part bottom="188.8" height="5.234" id="2" left="146.67" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="183.566" width="2.938"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="46" line-number="16" text="das"> <transkription-position bottom="190.597" height="11.11" id="0" left="153.338" top="179.487" width="12.806" writing-process-id="0"> <word-part bottom="188.8" height="7.203" id="0" left="153.488" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="181.597" width="4.281"/> <word-part bottom="188.8" height="5.234" id="1" left="158.642" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="183.566" width="3.812"/> <word-part bottom="188.8" height="5.234" id="2" left="163.056" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="183.566" width="2.938"/> <debug id="0" message="check for line breaks, diffx: 143.119, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="47" line-number="18" text="geistige"> <transkription-position bottom="214.119" height="11.11" id="0" left="19.693" top="203.009" width="29.681" writing-process-id="0"> <word-part bottom="212.4" height="7.281" id="0" left="19.843" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="205.119" width="4.203"/> <word-part bottom="212.4" height="5.234" id="1" left="24.437" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="207.166" width="3.703"/> <word-part bottom="212.4" height="6.844" id="2" left="29.031" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="205.557" width="2.094"/> <word-part bottom="212.4" height="5.234" id="3" left="31.585" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="207.166" width="2.938"/> <word-part bottom="212.4" height="6.422" id="4" left="35.259" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="205.978" width="2.781"/> <word-part bottom="212.4" height="6.844" id="5" left="38.373" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="205.557" width="2.094"/> <word-part bottom="212.4" height="7.281" id="6" left="40.927" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="205.119" width="4.203"/> <word-part bottom="212.4" height="5.234" id="7" left="45.521" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="207.166" width="3.703"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="48" line-number="18" text="Geschehen"> <transkription-position bottom="214.041" height="11.11" id="0" left="53.109" top="202.931" width="44.773" writing-process-id="0"> <word-part bottom="212.4" height="7.359" id="0" left="53.259" style-class="st9 st10" symbol-id="glyph4-41" text="G" top="205.041" width="6.188"/> <word-part bottom="212.4" height="5.234" id="1" left="60.263" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="207.166" width="3.703"/> <word-part bottom="212.4" height="5.234" id="2" left="64.857" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="207.166" width="2.938"/> <word-part bottom="212.4" height="5.234" id="3" left="68.531" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="207.166" width="3.531"/> <word-part bottom="212.4" height="7.125" id="4" left="72.945" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="205.275" width="4.891"/> <word-part bottom="212.4" height="5.234" id="5" left="78.299" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="207.166" width="3.703"/> <word-part bottom="212.4" height="7.125" id="6" left="82.893" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="205.275" width="4.891"/> <word-part bottom="212.4" height="5.234" id="7" left="88.247" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="207.166" width="3.703"/> <word-part bottom="212.4" height="5.312" id="8" left="92.841" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="207.088" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="49" line-number="18" text="einfacher"> <transkription-position bottom="214.275" height="11.11" id="0" left="101.189" top="203.165" width="37.306" writing-process-id="0"> <word-part bottom="212.4" height="5.234" id="0" left="101.339" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="207.166" width="3.703"/> <word-part bottom="212.4" height="6.844" id="1" left="105.933" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="205.557" width="2.094"/> <word-part bottom="212.4" height="5.312" id="2" left="108.487" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="207.088" width="4.891"/> <word-part bottom="212.4" height="7.125" id="3" left="113.841" style-class="st9 st10" symbol-id="glyph4-28" text="f" top="205.275" width="2.766"/> <word-part bottom="212.4" height="5.234" id="4" left="116.585" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="207.166" width="3.812"/> <word-part bottom="212.4" height="5.234" id="5" left="120.999" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="207.166" width="3.531"/> <word-part bottom="212.4" height="7.125" id="6" left="125.413" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="205.275" width="4.891"/> <word-part bottom="212.4" height="5.234" id="7" left="130.767" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="207.166" width="3.703"/> <word-part bottom="212.4" height="5.312" id="8" left="135.361" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="207.088" width="2.984"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="50" line-number="18" text="denken"> <transkription-position bottom="214.197" height="11.11" id="0" left="141.839" top="203.087" width="29.851" writing-process-id="0"> <word-part bottom="212.4" height="7.203" id="0" left="141.989" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="205.197" width="4.281"/> <word-part bottom="212.4" height="5.234" id="1" left="147.143" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="207.166" width="3.703"/> <word-part bottom="212.4" height="5.312" id="2" left="151.737" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="207.088" width="4.891"/> <word-part bottom="212.4" height="7.125" id="3" left="157.091" style-class="st9 st10" symbol-id="glyph4-22" text="k" top="205.275" width="4.781"/> <word-part bottom="212.4" height="5.234" id="4" left="162.055" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="207.166" width="3.703"/> <word-part bottom="212.4" height="5.312" id="5" left="166.649" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="207.088" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="51" line-number="18" text="als"> <transkription-position bottom="214.275" height="11.11" id="0" left="174.997" top="203.165" width="10.206" writing-process-id="0"> <word-part bottom="212.4" height="5.234" id="0" left="175.147" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="207.166" width="3.812"/> <word-part bottom="212.4" height="7.125" id="1" left="179.561" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="205.275" width="2.094"/> <word-part bottom="212.4" height="5.234" id="2" left="182.115" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="207.166" width="2.938"/> <debug id="0" message="check for line breaks, diffx: 162.116, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="52" line-number="20" text="es"> <transkription-position bottom="239.766" height="11.11" id="0" left="19.693" top="228.656" width="7.832" writing-process-id="0"> <word-part bottom="236.0" height="5.234" id="0" left="19.843" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="230.766" width="3.703"/> <word-part bottom="236.0" height="5.234" id="1" left="24.437" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="230.766" width="2.938"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="53" line-number="20" text="ist."> <transkription-position bottom="238.157" height="11.11" id="0" left="31.105" top="227.047" width="10.876" writing-process-id="0"> <word-part bottom="236.0" height="6.844" id="0" left="31.255" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="229.157" width="2.094"/> <word-part bottom="236.0" height="5.234" id="1" left="33.809" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="230.766" width="2.938"/> <word-part bottom="236.0" height="6.422" id="2" left="37.483" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="229.578" width="2.781"/> <word-part bottom="236.0" height="1.25" id="3" left="40.597" style-class="st9 st10" symbol-id="glyph4-19" text="." top="234.75" width="1.234"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="54" line-number="20" text="Erfahrung"> <transkription-position bottom="237.719" height="11.11" id="0" left="46.345" top="226.609" width="40.215" writing-process-id="0"> <word-part bottom="236.0" height="7.125" id="0" left="46.495" style-class="st9 st10" symbol-id="glyph4-32" text="E" top="228.875" width="4.547"/> <word-part bottom="236.0" height="5.312" id="1" left="52.019" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="230.688" width="2.984"/> <word-part bottom="236.0" height="7.125" id="2" left="55.503" style-class="st9 st10" symbol-id="glyph4-28" text="f" top="228.875" width="2.766"/> <word-part bottom="236.0" height="5.234" id="3" left="58.247" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="230.766" width="3.812"/> <word-part bottom="236.0" height="7.125" id="4" left="62.661" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="228.875" width="4.891"/> <word-part bottom="236.0" height="5.312" id="5" left="68.015" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="230.688" width="2.984"/> <word-part bottom="236.0" height="5.234" id="6" left="71.499" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="230.766" width="4.859"/> <word-part bottom="236.0" height="5.312" id="7" left="76.853" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="230.688" width="4.891"/> <word-part bottom="236.0" height="7.281" id="8" left="82.207" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="228.719" width="4.203"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="55" line-number="20" text="ist"> <transkription-position bottom="238.157" height="11.11" id="0" left="89.795" top="227.047" width="9.309" writing-process-id="0"> <word-part bottom="236.0" height="6.844" id="0" left="89.945" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="229.157" width="2.094"/> <word-part bottom="236.0" height="5.234" id="1" left="92.499" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="230.766" width="2.938"/> <word-part bottom="236.0" height="6.422" id="2" left="96.173" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="229.578" width="2.781"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="56" line-number="20" text="nur"> <transkription-position bottom="239.688" height="11.11" id="0" left="102.281" top="228.578" width="13.992" writing-process-id="0"> <word-part bottom="236.0" height="5.312" id="0" left="102.431" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="230.688" width="4.891"/> <word-part bottom="236.0" height="5.234" id="1" left="107.785" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="230.766" width="4.859"/> <word-part bottom="236.0" height="5.312" id="2" left="113.139" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="230.688" width="2.984"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="57" line-number="20" text="möglich"> <transkription-position bottom="237.719" height="11.11" id="0" left="119.617" top="226.609" width="32.205" writing-process-id="0"> <word-part bottom="236.0" height="5.312" id="0" left="119.767" style-class="st9 st10" symbol-id="glyph4-25" text="m" top="230.688" width="7.375"/> <word-part bottom="236.0" height="6.859" id="1" left="127.701" style-class="st9 st10" symbol-id="glyph4-35" text="ö" top="229.141" width="4.062"/> <word-part bottom="236.0" height="7.281" id="2" left="132.665" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="228.719" width="4.203"/> <word-part bottom="236.0" height="7.125" id="3" left="137.259" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="228.875" width="2.094"/> <word-part bottom="236.0" height="6.844" id="4" left="139.813" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="229.157" width="2.094"/> <word-part bottom="236.0" height="5.234" id="5" left="142.367" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="230.766" width="3.531"/> <word-part bottom="236.0" height="7.125" id="6" left="146.781" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="228.875" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="58" line-number="20" text="mit"> <transkription-position bottom="238.157" height="11.11" id="0" left="155.129" top="227.047" width="13.569" writing-process-id="0"> <word-part bottom="236.0" height="5.312" id="0" left="155.279" style-class="st9 st10" symbol-id="glyph4-25" text="m" top="230.688" width="7.375"/> <word-part bottom="236.0" height="6.844" id="1" left="163.213" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="229.157" width="2.094"/> <word-part bottom="236.0" height="6.422" id="2" left="165.767" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="229.578" width="2.781"/> <debug id="0" message="check for line breaks, diffx: 145.777, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="59" line-number="22" text="Hülfe"> <transkription-position bottom="261.475" height="11.11" id="0" left="19.693" top="250.365" width="21.659" writing-process-id="0"> <word-part bottom="259.6" height="7.125" id="0" left="19.843" style-class="st9 st10" symbol-id="glyph4-42" text="H" top="252.475" width="6.016"/> <word-part bottom="259.6" height="6.859" id="1" left="26.847" style-class="st9 st10" symbol-id="glyph4-39" text="ü" top="252.741" width="4.859"/> <word-part bottom="259.6" height="7.125" id="2" left="32.201" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="252.475" width="2.094"/> <word-part bottom="259.6" height="7.125" id="3" left="34.755" style-class="st9 st10" symbol-id="glyph4-28" text="f" top="252.475" width="2.766"/> <word-part bottom="259.6" height="5.234" id="4" left="37.499" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="254.366" width="3.703"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="60" line-number="22" text="von"> <transkription-position bottom="263.288" height="11.11" id="0" left="45.087" top="252.178" width="14.949" writing-process-id="0"> <word-part bottom="259.6" height="5.125" id="0" left="45.237" style-class="st9 st10" symbol-id="glyph4-29" text="v" top="254.475" width="4.797"/> <word-part bottom="259.6" height="5.234" id="1" left="50.031" style-class="st9 st10" symbol-id="glyph4-31" text="o" top="254.366" width="4.062"/> <word-part bottom="259.6" height="5.312" id="2" left="54.995" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="254.288" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="61" line-number="22" text="Gedächtniß:"> <transkription-position bottom="261.241" height="11.11" id="0" left="63.343" top="250.131" width="48.644" writing-process-id="0"> <word-part bottom="259.6" height="7.359" id="0" left="63.493" style-class="st9 st10" symbol-id="glyph4-41" text="G" top="252.241" width="6.188"/> <word-part bottom="259.6" height="5.234" id="1" left="70.497" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="254.366" width="3.703"/> <word-part bottom="259.6" height="7.203" id="2" left="75.091" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="252.397" width="4.281"/> <word-part bottom="259.6" height="6.859" id="3" left="80.245" style-class="st9 st10" symbol-id="glyph4-40" text="ä" top="252.741" width="3.812"/> <word-part bottom="259.6" height="5.234" id="4" left="84.659" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="254.366" width="3.531"/> <word-part bottom="259.6" height="7.125" id="5" left="89.073" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="252.475" width="4.891"/> <word-part bottom="259.6" height="6.422" id="6" left="94.427" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="253.178" width="2.781"/> <word-part bottom="259.6" height="5.312" id="7" left="97.541" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="254.288" width="4.891"/> <word-part bottom="259.6" height="6.844" id="8" left="102.895" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="252.757" width="2.094"/> <word-part bottom="259.6" height="7.312" id="9" left="105.449" style-class="st9 st10" symbol-id="glyph4-18" text="ß" top="252.288" width="4.516"/> <word-part bottom="259.6" height="4.75" id="10" left="110.603" style-class="st9 st10" symbol-id="glyph4-38" text=":" top="254.85" width="1.234"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="62" line-number="22" text="Gedächtniß"> <transkription-position bottom="261.241" height="11.11" id="0" left="116.351" top="250.131" width="46.772" writing-process-id="0"> <word-part bottom="259.6" height="7.359" id="0" left="116.501" style-class="st9 st10" symbol-id="glyph4-41" text="G" top="252.241" width="6.188"/> <word-part bottom="259.6" height="5.234" id="1" left="123.505" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="254.366" width="3.703"/> <word-part bottom="259.6" height="7.203" id="2" left="128.099" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="252.397" width="4.281"/> <word-part bottom="259.6" height="6.859" id="3" left="133.253" style-class="st9 st10" symbol-id="glyph4-40" text="ä" top="252.741" width="3.812"/> <word-part bottom="259.6" height="5.234" id="4" left="137.667" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="254.366" width="3.531"/> <word-part bottom="259.6" height="7.125" id="5" left="142.081" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="252.475" width="4.891"/> <word-part bottom="259.6" height="6.422" id="6" left="147.435" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="253.178" width="2.781"/> <word-part bottom="259.6" height="5.312" id="7" left="150.549" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="254.288" width="4.891"/> <word-part bottom="259.6" height="6.844" id="8" left="155.903" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="252.757" width="2.094"/> <word-part bottom="259.6" height="7.312" id="9" left="158.457" style-class="st9 st10" symbol-id="glyph4-18" text="ß" top="252.288" width="4.516"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="63" line-number="22" text="ist"> <transkription-position bottom="261.757" height="11.11" id="0" left="166.605" top="250.647" width="9.309" writing-process-id="0"> <word-part bottom="259.6" height="6.844" id="0" left="166.755" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="252.757" width="2.094"/> <word-part bottom="259.6" height="5.234" id="1" left="169.309" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="254.366" width="2.938"/> <word-part bottom="259.6" height="6.422" id="2" left="172.983" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="253.178" width="2.781"/> <debug id="0" message="check for line breaks, diffx: 152.997, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="64" line-number="24" text="nur"> <transkription-position bottom="286.888" height="11.11" id="0" left="19.693" top="275.778" width="13.992" writing-process-id="0"> <word-part bottom="283.2" height="5.312" id="0" left="19.843" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="277.888" width="4.891"/> <word-part bottom="283.2" height="5.234" id="1" left="25.197" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="277.966" width="4.859"/> <word-part bottom="283.2" height="5.312" id="2" left="30.551" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="277.888" width="2.984"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="65" line-number="24" text="möglich"> <transkription-position bottom="284.919" height="11.11" id="0" left="37.029" top="273.809" width="32.205" writing-process-id="0"> <word-part bottom="283.2" height="5.312" id="0" left="37.179" style-class="st9 st10" symbol-id="glyph4-25" text="m" top="277.888" width="7.375"/> <word-part bottom="283.2" height="6.859" id="1" left="45.113" style-class="st9 st10" symbol-id="glyph4-35" text="ö" top="276.341" width="4.062"/> <word-part bottom="283.2" height="7.281" id="2" left="50.077" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="275.919" width="4.203"/> <word-part bottom="283.2" height="7.125" id="3" left="54.671" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="276.075" width="2.094"/> <word-part bottom="283.2" height="6.844" id="4" left="57.225" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="276.357" width="2.094"/> <word-part bottom="283.2" height="5.234" id="5" left="59.779" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="277.966" width="3.531"/> <word-part bottom="283.2" height="7.125" id="6" left="64.193" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="276.075" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="66" line-number="24" text="vermöge"> <transkription-position bottom="284.919" height="11.11" id="0" left="72.541" top="273.809" width="34.367" writing-process-id="0"> <word-part bottom="283.2" height="5.125" id="0" left="72.691" style-class="st9 st10" symbol-id="glyph4-29" text="v" top="278.075" width="4.797"/> <word-part bottom="283.2" height="5.234" id="1" left="77.485" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="277.966" width="3.703"/> <word-part bottom="283.2" height="5.312" id="2" left="82.079" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="277.888" width="2.984"/> <word-part bottom="283.2" height="5.312" id="3" left="85.563" style-class="st9 st10" symbol-id="glyph4-25" text="m" top="277.888" width="7.375"/> <word-part bottom="283.2" height="6.859" id="4" left="93.497" style-class="st9 st10" symbol-id="glyph4-35" text="ö" top="276.341" width="4.062"/> <word-part bottom="283.2" height="7.281" id="5" left="98.461" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="275.919" width="4.203"/> <word-part bottom="283.2" height="5.234" id="6" left="103.055" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="277.966" width="3.703"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="67" line-number="24" text="einer"> <transkription-position bottom="285.357" height="11.11" id="0" left="110.643" top="274.247" width="20.38" writing-process-id="0"> <word-part bottom="283.2" height="5.234" id="0" left="110.793" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="277.966" width="3.703"/> <word-part bottom="283.2" height="6.844" id="1" left="115.387" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="276.357" width="2.094"/> <word-part bottom="283.2" height="5.312" id="2" left="117.941" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="277.888" width="4.891"/> <word-part bottom="283.2" height="5.234" id="3" left="123.295" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="277.966" width="3.703"/> <word-part bottom="283.2" height="5.312" id="4" left="127.889" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="277.888" width="2.984"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="68" line-number="24" text="Abkürzung"> <transkription-position bottom="284.919" height="11.11" id="0" left="134.367" top="273.809" width="44.835" writing-process-id="0"> <word-part bottom="283.2" height="7.125" id="0" left="134.517" style-class="st9 st10" symbol-id="glyph4-30" text="A" top="276.075" width="6.359"/> <word-part bottom="283.2" height="7.203" id="1" left="140.781" style-class="st9 st10" symbol-id="glyph4-23" text="b" top="275.997" width="4.281"/> <word-part bottom="283.2" height="7.125" id="2" left="145.745" style-class="st9 st10" symbol-id="glyph4-22" text="k" top="276.075" width="4.781"/> <word-part bottom="283.2" height="6.859" id="3" left="150.709" style-class="st9 st10" symbol-id="glyph4-39" text="ü" top="276.341" width="4.859"/> <word-part bottom="283.2" height="5.312" id="4" left="156.063" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="277.888" width="2.984"/> <word-part bottom="283.2" height="5.062" id="5" left="159.547" style-class="st9 st10" symbol-id="glyph4-12" text="z" top="278.138" width="4.125"/> <word-part bottom="283.2" height="5.234" id="6" left="164.141" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="277.966" width="4.859"/> <word-part bottom="283.2" height="5.312" id="7" left="169.495" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="277.888" width="4.891"/> <word-part bottom="283.2" height="7.281" id="8" left="174.849" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="275.919" width="4.203"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="69" line-number="24" text="eines"> <transkription-position bottom="285.357" height="11.11" id="0" left="182.437" top="274.247" width="20.334" writing-process-id="0"> <word-part bottom="283.2" height="5.234" id="0" left="182.587" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="277.966" width="3.703"/> <word-part bottom="283.2" height="6.844" id="1" left="187.181" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="276.357" width="2.094"/> <word-part bottom="283.2" height="5.312" id="2" left="189.735" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="277.888" width="4.891"/> <word-part bottom="283.2" height="5.234" id="3" left="195.089" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="277.966" width="3.703"/> <word-part bottom="283.2" height="5.234" id="4" left="199.683" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="277.966" width="2.938"/> <debug id="0" message="check for line breaks, diffx: 179.676, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="70" line-number="26" text="geistigen"> <transkription-position bottom="308.519" height="11.11" id="0" left="19.693" top="297.409" width="35.463" writing-process-id="0"> <word-part bottom="306.8" height="7.281" id="0" left="19.843" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="299.519" width="4.203"/> <word-part bottom="306.8" height="5.234" id="1" left="24.437" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="301.566" width="3.703"/> <word-part bottom="306.8" height="6.844" id="2" left="29.031" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="299.957" width="2.094"/> <word-part bottom="306.8" height="5.234" id="3" left="31.585" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="301.566" width="2.938"/> <word-part bottom="306.8" height="6.422" id="4" left="35.259" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="300.378" width="2.781"/> <word-part bottom="306.8" height="6.844" id="5" left="38.373" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="299.957" width="2.094"/> <word-part bottom="306.8" height="7.281" id="6" left="40.927" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="299.519" width="4.203"/> <word-part bottom="306.8" height="5.234" id="7" left="45.521" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="301.566" width="3.703"/> <word-part bottom="306.8" height="5.312" id="8" left="50.115" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="301.488" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="71" line-number="26" text="V"> <transkription-position bottom="308.613" height="11.11" id="0" left="58.463" top="297.503" width="6.675" writing-process-id="0"> <word-part bottom="306.8" height="7.188" id="0" left="58.613" style-class="st9 st10" symbol-id="glyph4-43" text="V" top="299.613" width="6.375"/> <debug id="0" message="word.split"/> </transkription-position> </word> <word deleted="false" id="72" line-number="26" text="organgs"> <transkription-position bottom="308.518" height="11.11" id="0" left="63.809" top="297.408" width="30.64" writing-process-id="0"> <word-part bottom="306.8" height="5.234" id="0" left="63.959" style-class="st9 st10" symbol-id="glyph4-31" text="o" top="301.566" width="4.062"/> <word-part bottom="306.799" height="5.312" id="1" left="68.921" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="301.487" width="2.984"/> <debug id="0" message="update word from tests_svgscripts/fix_missing_glyphs.py"/> <word-part bottom="306.799" height="7.281" id="2" left="72.405" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="299.518" width="4.203"/> <word-part bottom="306.799" height="5.234" id="3" left="76.999" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="301.565" width="3.812"/> <word-part bottom="306.799" height="5.312" id="4" left="81.413" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="301.487" width="4.891"/> <word-part bottom="306.799" height="7.281" id="5" left="86.767" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="299.518" width="4.203"/> <word-part bottom="306.799" height="5.234" id="6" left="91.361" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="301.565" width="2.938"/> </transkription-position> </word> <word deleted="false" id="73" line-number="26" text="zum"> <transkription-position bottom="310.488" height="11.11" id="0" left="98.03" top="299.378" width="17.623" writing-process-id="0"> <word-part bottom="306.8" height="5.062" id="0" left="98.18" style-class="st9 st10" symbol-id="glyph4-12" text="z" top="301.738" width="4.125"/> <word-part bottom="306.8" height="5.234" id="1" left="102.774" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="301.566" width="4.859"/> <word-part bottom="306.8" height="5.312" id="2" left="108.128" style-class="st9 st10" symbol-id="glyph4-25" text="m" top="301.488" width="7.375"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="74" line-number="26" text="Zeichen."> <transkription-position bottom="308.675" height="11.11" id="0" left="119.056" top="297.565" width="33.748" writing-process-id="0"> <word-part bottom="306.8" height="7.125" id="0" left="119.206" style-class="st9 st10" symbol-id="glyph4-44" text="Z" top="299.675" width="4.875"/> <word-part bottom="306.8" height="5.234" id="1" left="124.55" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="301.566" width="3.703"/> <word-part bottom="306.8" height="6.844" id="2" left="129.144" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="299.957" width="2.094"/> <word-part bottom="306.8" height="5.234" id="3" left="131.698" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="301.566" width="3.531"/> <word-part bottom="306.8" height="7.125" id="4" left="136.112" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="299.675" width="4.891"/> <word-part bottom="306.8" height="5.234" id="5" left="141.466" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="301.566" width="3.703"/> <word-part bottom="306.8" height="5.312" id="6" left="146.06" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="301.488" width="4.891"/> <word-part bottom="306.8" height="1.25" id="7" left="151.42" style-class="st9 st10" symbol-id="glyph4-19" text="." top="305.55" width="1.234"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="75" line-number="26" text="$"> <transkription-position bottom="310.129" height="11.11" id="0" left="185.456" top="299.019" width="5.941" writing-process-id="0"> <word-part bottom="306.8" height="5.672" id="0" left="185.606" style-class="st13 st10" symbol-id="glyph6-1" text="$" top="301.129" width="5.641"/> <debug id="0" message="check for line breaks, diffx: 148.755, diffy: 23.601, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="76" line-number="28" text="Die"> <transkription-position bottom="332.275" height="11.11" id="0" left="36.701" top="321.165" width="13.571" writing-process-id="0"> <word-part bottom="330.4" height="7.125" id="0" left="36.851" style-class="st9 st10" symbol-id="glyph4-36" text="D" top="323.275" width="5.859"/> <word-part bottom="330.4" height="6.844" id="1" left="43.865" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="323.557" width="2.094"/> <word-part bottom="330.4" height="5.234" id="2" left="46.419" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="325.166" width="3.703"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="77" line-number="28" text="Zeichenschrift."> <transkription-position bottom="332.275" height="11.11" id="0" left="54.007" top="321.165" width="59.08" writing-process-id="0"> <word-part bottom="330.4" height="7.125" id="0" left="54.157" style-class="st9 st10" symbol-id="glyph4-44" text="Z" top="323.275" width="4.875"/> <word-part bottom="330.4" height="5.234" id="1" left="59.501" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="325.166" width="3.703"/> <word-part bottom="330.4" height="6.844" id="2" left="64.095" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="323.557" width="2.094"/> <word-part bottom="330.4" height="5.234" id="3" left="66.649" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="325.166" width="3.531"/> <word-part bottom="330.4" height="7.125" id="4" left="71.063" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="323.275" width="4.891"/> <word-part bottom="330.4" height="5.234" id="5" left="76.417" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="325.166" width="3.703"/> <word-part bottom="330.4" height="5.312" id="6" left="81.011" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="325.088" width="4.891"/> <word-part bottom="330.4" height="5.234" id="7" left="86.365" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="325.166" width="2.938"/> <word-part bottom="330.4" height="5.234" id="8" left="90.039" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="325.166" width="3.531"/> <word-part bottom="330.4" height="7.125" id="9" left="94.453" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="323.275" width="4.891"/> <word-part bottom="330.4" height="5.312" id="10" left="99.807" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="325.088" width="2.984"/> <word-part bottom="330.4" height="6.844" id="11" left="103.291" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="323.557" width="2.094"/> <word-part bottom="330.4" height="7.125" id="12" left="105.845" style-class="st9 st10" symbol-id="glyph4-28" text="f" top="323.275" width="2.766"/> <word-part bottom="330.4" height="6.422" id="13" left="108.589" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="323.979" width="2.781"/> <word-part bottom="330.4" height="1.25" id="14" left="111.703" style-class="st9 st10" symbol-id="glyph4-19" text="." top="329.15" width="1.234"/> <debug id="0" message="check for line breaks, diffx: 91.786, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="78" line-number="30" text="Erklärung:"> <transkription-position bottom="355.719" height="11.11" id="0" left="19.693" top="344.609" width="41.263" writing-process-id="0"> <word-part bottom="354.0" height="7.125" id="0" left="19.843" style-class="st9 st10" symbol-id="glyph4-32" text="E" top="346.875" width="4.547"/> <word-part bottom="354.0" height="5.312" id="1" left="25.367" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="348.688" width="2.984"/> <word-part bottom="354.0" height="7.125" id="2" left="28.851" style-class="st9 st10" symbol-id="glyph4-22" text="k" top="346.875" width="4.781"/> <word-part bottom="354.0" height="7.125" id="3" left="33.815" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="346.875" width="2.094"/> <word-part bottom="354.0" height="6.859" id="4" left="36.369" style-class="st9 st10" symbol-id="glyph4-40" text="ä" top="347.141" width="3.812"/> <word-part bottom="354.0" height="5.312" id="5" left="40.783" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="348.688" width="2.984"/> <word-part bottom="354.0" height="5.234" id="6" left="44.27" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="348.766" width="4.859"/> <word-part bottom="354.0" height="5.312" id="7" left="49.624" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="348.688" width="4.891"/> <word-part bottom="354.0" height="7.281" id="8" left="54.978" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="346.719" width="4.203"/> <word-part bottom="354.0" height="4.75" id="9" left="59.572" style-class="st9 st10" symbol-id="glyph4-38" text=":" top="349.25" width="1.234"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="79" line-number="30" text="das"> <transkription-position bottom="355.797" height="11.11" id="0" left="65.319" top="344.687" width="12.806" writing-process-id="0"> <word-part bottom="354.0" height="7.203" id="0" left="65.469" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="346.797" width="4.281"/> <word-part bottom="354.0" height="5.234" id="1" left="70.623" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="348.766" width="3.812"/> <word-part bottom="354.0" height="5.234" id="2" left="75.037" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="348.766" width="2.938"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="80" line-number="30" text="ist"> <transkription-position bottom="356.157" height="11.11" id="0" left="81.705" top="345.047" width="9.31" writing-process-id="0"> <word-part bottom="354.0" height="6.844" id="0" left="81.855" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="347.157" width="2.094"/> <word-part bottom="354.0" height="5.234" id="1" left="84.409" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="348.766" width="2.938"/> <word-part bottom="354.0" height="6.422" id="2" left="88.084" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="347.579" width="2.781"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="81" line-number="30" text="der"> <transkription-position bottom="355.797" height="11.11" id="0" left="94.191" top="344.687" width="13.032" writing-process-id="0"> <word-part bottom="354.0" height="7.203" id="0" left="94.341" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="346.797" width="4.281"/> <word-part bottom="354.0" height="5.234" id="1" left="99.495" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="348.766" width="3.703"/> <word-part bottom="354.0" height="5.312" id="2" left="104.089" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="348.688" width="2.984"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="82" line-number="30" text="Ausdruck"> <transkription-position bottom="355.797" height="11.11" id="0" left="110.568" top="344.687" width="38.779" writing-process-id="0"> <word-part bottom="354.0" height="7.125" id="0" left="110.718" style-class="st9 st10" symbol-id="glyph4-30" text="A" top="346.875" width="6.359"/> <word-part bottom="354.0" height="5.234" id="1" left="116.981" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="348.766" width="4.859"/> <word-part bottom="354.0" height="5.234" id="2" left="122.335" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="348.766" width="2.938"/> <word-part bottom="354.0" height="7.203" id="3" left="126.01" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="346.797" width="4.281"/> <word-part bottom="354.0" height="5.312" id="4" left="131.163" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="348.688" width="2.984"/> <word-part bottom="354.0" height="5.234" id="5" left="134.648" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="348.766" width="4.859"/> <word-part bottom="354.0" height="5.234" id="6" left="140.001" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="348.766" width="3.531"/> <word-part bottom="354.0" height="7.125" id="7" left="144.416" style-class="st9 st10" symbol-id="glyph4-22" text="k" top="346.875" width="4.781"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="83" line-number="30" text="eines"> <transkription-position bottom="356.157" height="11.11" id="0" left="152.373" top="345.047" width="20.334" writing-process-id="0"> <word-part bottom="354.0" height="5.234" id="0" left="152.523" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="348.766" width="3.703"/> <word-part bottom="354.0" height="6.844" id="1" left="157.118" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="347.157" width="2.094"/> <word-part bottom="354.0" height="5.312" id="2" left="159.672" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="348.688" width="4.891"/> <word-part bottom="354.0" height="5.234" id="3" left="165.025" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="348.766" width="3.703"/> <word-part bottom="354.0" height="5.234" id="4" left="169.619" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="348.766" width="2.938"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="84" line-number="30" text="neuen"> <transkription-position bottom="357.688" height="11.11" id="0" left="176.288" top="346.578" width="25.086" writing-process-id="0"> <word-part bottom="354.0" height="5.312" id="0" left="176.438" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="348.688" width="4.891"/> <word-part bottom="354.0" height="5.234" id="1" left="181.791" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="348.766" width="3.703"/> <word-part bottom="354.0" height="5.234" id="2" left="186.386" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="348.766" width="4.859"/> <word-part bottom="354.0" height="5.234" id="3" left="191.739" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="348.766" width="3.703"/> <word-part bottom="354.0" height="5.312" id="4" left="196.333" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="348.688" width="4.891"/> <debug id="0" message="check for line breaks, diffx: 182.025, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="85" line-number="32" text="Dings"> <transkription-position bottom="379.319" height="11.11" id="0" left="14.024" top="368.209" width="22.753" writing-process-id="0"> <word-part bottom="377.6" height="7.125" id="0" left="14.174" style-class="st9 st10" symbol-id="glyph4-36" text="D" top="370.475" width="5.859"/> <word-part bottom="377.6" height="6.844" id="1" left="21.187" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="370.757" width="2.094"/> <word-part bottom="377.6" height="5.312" id="2" left="23.741" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="372.288" width="4.891"/> <word-part bottom="377.6" height="7.281" id="3" left="29.095" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="370.319" width="4.203"/> <word-part bottom="377.6" height="5.234" id="4" left="33.689" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="372.366" width="2.938"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="86" line-number="32" text="vermittelst"> <transkription-position bottom="379.475" height="11.11" id="0" left="40.357" top="368.365" width="43.491" writing-process-id="0"> <word-part bottom="377.6" height="5.125" id="0" left="40.507" style-class="st9 st10" symbol-id="glyph4-29" text="v" top="372.475" width="4.797"/> <word-part bottom="377.6" height="5.234" id="1" left="45.301" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="372.366" width="3.703"/> <word-part bottom="377.6" height="5.312" id="2" left="49.895" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="372.288" width="2.984"/> <word-part bottom="377.6" height="5.312" id="3" left="53.379" style-class="st9 st10" symbol-id="glyph4-25" text="m" top="372.288" width="7.375"/> <word-part bottom="377.6" height="6.844" id="4" left="61.313" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="370.757" width="2.094"/> <word-part bottom="377.6" height="6.422" id="5" left="63.867" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="371.179" width="2.781"/> <word-part bottom="377.6" height="6.422" id="6" left="66.981" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="371.179" width="2.781"/> <word-part bottom="377.6" height="5.234" id="7" left="70.096" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="372.366" width="3.703"/> <word-part bottom="377.6" height="7.125" id="8" left="74.689" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="370.475" width="2.094"/> <word-part bottom="377.6" height="5.234" id="9" left="77.243" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="372.366" width="2.938"/> <word-part bottom="377.6" height="6.422" id="10" left="80.917" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="371.179" width="2.781"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="87" line-number="32" text="der"> <transkription-position bottom="379.397" height="11.11" id="0" left="87.025" top="368.287" width="13.032" writing-process-id="0"> <word-part bottom="377.6" height="7.203" id="0" left="87.175" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="370.397" width="4.281"/> <word-part bottom="377.6" height="5.234" id="1" left="92.329" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="372.366" width="3.703"/> <word-part bottom="377.6" height="5.312" id="2" left="96.923" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="372.288" width="2.984"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="88" line-number="32" text="Zeichen"> <transkription-position bottom="379.475" height="11.11" id="0" left="103.402" top="368.365" width="32.044" writing-process-id="0"> <word-part bottom="377.6" height="7.125" id="0" left="103.552" style-class="st9 st10" symbol-id="glyph4-44" text="Z" top="370.475" width="4.875"/> <word-part bottom="377.6" height="5.234" id="1" left="108.895" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="372.366" width="3.703"/> <word-part bottom="377.6" height="6.844" id="2" left="113.489" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="370.757" width="2.094"/> <word-part bottom="377.6" height="5.234" id="3" left="116.043" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="372.366" width="3.531"/> <word-part bottom="377.6" height="7.125" id="4" left="120.458" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="370.475" width="4.891"/> <word-part bottom="377.6" height="5.234" id="5" left="125.811" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="372.366" width="3.703"/> <word-part bottom="377.6" height="5.312" id="6" left="130.405" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="372.288" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="89" line-number="32" text="von"> <transkription-position bottom="381.288" height="11.11" id="0" left="138.754" top="370.178" width="14.948" writing-process-id="0"> <word-part bottom="377.6" height="5.125" id="0" left="138.904" style-class="st9 st10" symbol-id="glyph4-29" text="v" top="372.475" width="4.797"/> <word-part bottom="377.6" height="5.234" id="1" left="143.697" style-class="st9 st10" symbol-id="glyph4-31" text="o" top="372.366" width="4.062"/> <word-part bottom="377.6" height="5.312" id="2" left="148.661" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="372.288" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="90" line-number="32" text="schon"> <transkription-position bottom="379.475" height="11.11" id="0" left="157.01" top="368.365" width="23.596" writing-process-id="0"> <word-part bottom="377.6" height="5.234" id="0" left="157.16" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="372.366" width="2.938"/> <word-part bottom="377.6" height="5.234" id="1" left="160.833" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="372.366" width="3.531"/> <word-part bottom="377.6" height="7.125" id="2" left="165.248" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="370.475" width="4.891"/> <word-part bottom="377.6" height="5.234" id="3" left="170.601" style-class="st9 st10" symbol-id="glyph4-31" text="o" top="372.366" width="4.062"/> <word-part bottom="377.6" height="5.312" id="4" left="175.565" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="372.288" width="4.891"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="91" line-number="32" text="bekannten"> <transkription-position bottom="379.397" height="11.11" id="0" left="183.914" top="368.287" width="42.543" writing-process-id="0"> <word-part bottom="377.6" height="7.203" id="0" left="184.064" style-class="st9 st10" symbol-id="glyph4-23" text="b" top="370.397" width="4.281"/> <word-part bottom="377.6" height="5.234" id="1" left="189.028" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="372.366" width="3.703"/> <word-part bottom="377.6" height="7.125" id="2" left="193.621" style-class="st9 st10" symbol-id="glyph4-22" text="k" top="370.475" width="4.781"/> <word-part bottom="377.6" height="5.234" id="3" left="198.585" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="372.366" width="3.812"/> <word-part bottom="377.6" height="5.312" id="4" left="202.999" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="372.288" width="4.891"/> <word-part bottom="377.6" height="5.312" id="5" left="208.353" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="372.288" width="4.891"/> <word-part bottom="377.6" height="6.422" id="6" left="213.708" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="371.179" width="2.781"/> <word-part bottom="377.6" height="5.234" id="7" left="216.821" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="372.366" width="3.703"/> <word-part bottom="377.6" height="5.312" id="8" left="221.416" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="372.288" width="4.891"/> <debug id="0" message="check for line breaks, diffx: 207.045, diffy: 23.601, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="92" line-number="34" text="Dingen"> <transkription-position bottom="402.919" height="11.11" id="0" left="14.024" top="391.809" width="29.3" writing-process-id="0"> <word-part bottom="401.2" height="7.125" id="0" left="14.174" style-class="st9 st10" symbol-id="glyph4-36" text="D" top="394.075" width="5.859"/> <word-part bottom="401.2" height="6.844" id="1" left="21.187" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="394.357" width="2.094"/> <word-part bottom="401.2" height="5.312" id="2" left="23.741" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="395.888" width="4.891"/> <word-part bottom="401.2" height="7.281" id="3" left="29.095" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="393.919" width="4.203"/> <word-part bottom="401.2" height="5.234" id="4" left="33.689" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="395.966" width="3.703"/> <word-part bottom="401.2" height="5.312" id="5" left="38.283" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="395.888" width="4.891"/> <debug id="0" message="check for line breaks, diffx: 18.42, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="93" line-number="36" text="Daß"> <transkription-position bottom="426.488" height="11.11" id="0" left="19.692" top="415.378" width="16.245" writing-process-id="0"> <word-part bottom="424.8" height="7.125" id="0" left="19.842" style-class="st9 st10" symbol-id="glyph4-36" text="D" top="417.675" width="5.859"/> <word-part bottom="424.8" height="5.234" id="1" left="26.857" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="419.566" width="3.812"/> <word-part bottom="424.8" height="7.312" id="2" left="31.271" style-class="st9 st10" symbol-id="glyph4-18" text="ß" top="417.488" width="4.516"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="94" line-number="36" text="wir"> <transkription-position bottom="426.957" height="11.11" id="0" left="39.419" top="415.847" width="13.401" writing-process-id="0"> <word-part bottom="424.8" height="5.125" id="0" left="39.569" style-class="st9 st10" symbol-id="glyph4-15" text="w" top="419.675" width="7.562"/> <word-part bottom="424.8" height="6.844" id="1" left="47.132" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="417.957" width="2.094"/> <word-part bottom="424.8" height="5.312" id="2" left="49.686" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="419.488" width="2.984"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="95" line-number="36" text="wirkende"> <transkription-position bottom="426.597" height="11.11" id="0" left="56.164" top="415.487" width="37.672" writing-process-id="0"> <word-part bottom="424.8" height="5.125" id="0" left="56.314" style-class="st9 st10" symbol-id="glyph4-15" text="w" top="419.675" width="7.562"/> <word-part bottom="424.8" height="6.844" id="1" left="63.879" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="417.957" width="2.094"/> <word-part bottom="424.8" height="5.312" id="2" left="66.432" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="419.488" width="2.984"/> <word-part bottom="424.8" height="7.125" id="3" left="69.916" style-class="st9 st10" symbol-id="glyph4-22" text="k" top="417.675" width="4.781"/> <word-part bottom="424.8" height="5.234" id="4" left="74.88" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="419.566" width="3.703"/> <word-part bottom="424.8" height="5.312" id="5" left="79.474" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="419.488" width="4.891"/> <word-part bottom="424.8" height="7.203" id="6" left="84.828" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="417.597" width="4.281"/> <word-part bottom="424.8" height="5.234" id="7" left="89.983" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="419.566" width="3.703"/> <debug id="0" message="check for line breaks, diffx: 7.809, diffy: 0.0, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="96" line-number="36" text="Wesen,"> <transkription-position bottom="426.613" height="11.11" id="0" left="97.58" top="415.503" width="28.631" writing-process-id="0"> <word-part bottom="424.8" height="7.188" id="0" left="97.73" style-class="st9 st10" symbol-id="glyph4-45" text="W" top="417.613" width="9.094"/> <word-part bottom="424.8" height="5.234" id="1" left="106.407" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="419.566" width="3.703"/> <word-part bottom="424.8" height="5.234" id="2" left="111.001" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="419.566" width="2.938"/> <word-part bottom="424.8" height="5.234" id="3" left="114.675" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="419.566" width="3.703"/> <word-part bottom="424.8" height="5.312" id="4" left="119.269" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="419.488" width="4.891"/> <word-part bottom="424.8" height="3.234" id="5" left="124.623" style-class="st9 st10" symbol-id="glyph4-21" text="," top="421.566" width="1.438"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="97" line-number="36" text="Kräfte"> <transkription-position bottom="426.675" height="11.11" id="0" left="130.371" top="415.565" width="23.843" writing-process-id="0"> <word-part bottom="424.8" height="7.125" id="0" left="130.521" style-class="st9 st10" symbol-id="glyph4-26" text="K" top="417.675" width="5.422"/> <word-part bottom="424.8" height="5.312" id="1" left="136.605" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="419.488" width="2.984"/> <word-part bottom="424.8" height="6.859" id="2" left="140.089" style-class="st9 st10" symbol-id="glyph4-40" text="ä" top="417.941" width="3.812"/> <word-part bottom="424.8" height="7.125" id="3" left="144.503" style-class="st9 st10" symbol-id="glyph4-28" text="f" top="417.675" width="2.766"/> <word-part bottom="424.8" height="6.422" id="4" left="147.247" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="418.379" width="2.781"/> <word-part bottom="424.8" height="5.234" id="5" left="150.361" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="419.566" width="3.703"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="98" line-number="36" text="sind,"> <transkription-position bottom="426.597" height="11.11" id="0" left="157.949" top="415.487" width="18.474" writing-process-id="0"> <word-part bottom="424.8" height="5.234" id="0" left="158.099" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="419.566" width="2.938"/> <word-part bottom="424.8" height="6.844" id="1" left="161.773" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="417.957" width="2.094"/> <word-part bottom="424.8" height="5.312" id="2" left="164.327" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="419.488" width="4.891"/> <word-part bottom="424.8" height="7.203" id="3" left="169.681" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="417.597" width="4.281"/> <word-part bottom="424.8" height="3.234" id="4" left="174.835" style-class="st9 st10" symbol-id="glyph4-21" text="," top="421.566" width="1.438"/> <debug id="0" message="check for line breaks, diffx: 160.595, diffy: 23.601, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="99" line-number="38" text="ist"> <transkription-position bottom="450.557" height="11.11" id="0" left="14.024" top="439.447" width="9.309" writing-process-id="0"> <word-part bottom="448.4" height="6.844" id="0" left="14.174" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="441.557" width="2.094"/> <word-part bottom="448.4" height="5.234" id="1" left="16.728" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="443.166" width="2.938"/> <word-part bottom="448.4" height="6.422" id="2" left="20.402" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="441.979" width="2.781"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="100" line-number="38" text="unser"> <transkription-position bottom="452.088" height="11.11" id="0" left="26.51" top="440.978" width="22.26" writing-process-id="0"> <word-part bottom="448.4" height="5.234" id="0" left="26.66" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="443.166" width="4.859"/> <word-part bottom="448.4" height="5.312" id="1" left="32.014" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="443.088" width="4.891"/> <word-part bottom="448.4" height="5.234" id="2" left="37.368" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="443.166" width="2.938"/> <word-part bottom="448.4" height="5.234" id="3" left="41.042" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="443.166" width="3.703"/> <word-part bottom="448.4" height="5.312" id="4" left="45.636" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="443.088" width="2.984"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="101" line-number="38" text="Grundglaube."> <transkription-position bottom="450.041" height="11.11" id="0" left="52.114" top="438.931" width="54.358" writing-process-id="0"> <word-part bottom="448.4" height="7.359" id="0" left="52.264" style-class="st9 st10" symbol-id="glyph4-41" text="G" top="441.041" width="6.188"/> <word-part bottom="448.4" height="5.312" id="1" left="59.268" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="443.088" width="2.984"/> <word-part bottom="448.4" height="5.234" id="2" left="62.752" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="443.166" width="4.859"/> <word-part bottom="448.4" height="5.312" id="3" left="68.106" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="443.088" width="4.891"/> <word-part bottom="448.4" height="7.203" id="4" left="73.46" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="441.197" width="4.281"/> <word-part bottom="448.4" height="7.281" id="5" left="78.614" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="441.119" width="4.203"/> <word-part bottom="448.4" height="7.125" id="6" left="83.208" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="441.275" width="2.094"/> <word-part bottom="448.4" height="5.234" id="7" left="85.762" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="443.166" width="3.812"/> <word-part bottom="448.4" height="5.234" id="8" left="90.176" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="443.166" width="4.859"/> <word-part bottom="448.4" height="7.203" id="9" left="95.53" style-class="st9 st10" symbol-id="glyph4-23" text="b" top="441.197" width="4.281"/> <word-part bottom="448.4" height="5.234" id="10" left="100.494" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="443.166" width="3.703"/> <word-part bottom="448.4" height="1.25" id="11" left="105.088" style-class="st9 st10" symbol-id="glyph4-19" text="." top="447.15" width="1.234"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="102" line-number="38" text="Frei:"> <transkription-position bottom="450.275" height="11.11" id="0" left="110.836" top="439.165" width="17.147" writing-process-id="0"> <word-part bottom="448.4" height="7.125" id="0" left="110.986" style-class="st9 st10" symbol-id="glyph4-46" text="F" top="441.275" width="4.266"/> <word-part bottom="448.4" height="5.312" id="1" left="115.96" style-class="st9 st10" symbol-id="glyph4-11" text="r" top="443.088" width="2.984"/> <word-part bottom="448.4" height="5.234" id="2" left="119.448" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="443.166" width="3.703"/> <word-part bottom="448.4" height="6.844" id="3" left="124.042" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="441.557" width="2.094"/> <word-part bottom="448.4" height="4.75" id="4" left="126.599" style-class="st9 st10" symbol-id="glyph4-38" text=":" top="443.65" width="1.234"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="103" line-number="38" text="heißt"> <transkription-position bottom="450.088" height="11.11" id="0" left="132.347" top="438.978" width="20.737" writing-process-id="0"> <word-part bottom="448.4" height="7.125" id="0" left="132.497" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="441.275" width="4.891"/> <word-part bottom="448.4" height="5.234" id="1" left="137.851" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="443.166" width="3.703"/> <word-part bottom="448.4" height="6.844" id="2" left="142.445" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="441.557" width="2.094"/> <word-part bottom="448.4" height="7.312" id="3" left="144.999" style-class="st9 st10" symbol-id="glyph4-18" text="ß" top="441.088" width="4.516"/> <word-part bottom="448.4" height="6.422" id="4" left="150.153" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="441.979" width="2.781"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="104" line-number="38" text="„nicht"> <transkription-position bottom="450.275" height="11.11" id="0" left="156.261" top="439.165" width="25.351" writing-process-id="0"> <word-part bottom="448.4" height="2.75" id="0" left="156.411" style-class="st9 st10" symbol-id="glyph4-47" text="„" top="445.65" width="2.938"/> <word-part bottom="448.4" height="5.312" id="1" left="161.005" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="443.088" width="4.891"/> <word-part bottom="448.4" height="6.844" id="2" left="166.359" style-class="st9 st10" symbol-id="glyph4-16" text="i" top="441.557" width="2.094"/> <word-part bottom="448.4" height="5.234" id="3" left="168.913" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="443.166" width="3.531"/> <word-part bottom="448.4" height="7.125" id="4" left="173.327" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="441.275" width="4.891"/> <word-part bottom="448.4" height="6.422" id="5" left="178.681" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="441.979" width="2.781"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="105" line-number="38" text="gestoßen"> <transkription-position bottom="450.088" height="11.11" id="0" left="184.789" top="438.978" width="35.879" writing-process-id="0"> <word-part bottom="448.4" height="7.281" id="0" left="184.939" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="441.119" width="4.203"/> <word-part bottom="448.4" height="5.234" id="1" left="189.533" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="443.166" width="3.703"/> <word-part bottom="448.4" height="5.234" id="2" left="194.127" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="443.166" width="2.938"/> <word-part bottom="448.4" height="6.422" id="3" left="197.801" style-class="st9 st10" symbol-id="glyph4-6" text="t" top="441.979" width="2.781"/> <word-part bottom="448.4" height="5.234" id="4" left="200.915" style-class="st9 st10" symbol-id="glyph4-31" text="o" top="443.166" width="4.062"/> <word-part bottom="448.4" height="7.312" id="5" left="205.879" style-class="st9 st10" symbol-id="glyph4-18" text="ß" top="441.088" width="4.516"/> <word-part bottom="448.4" height="5.234" id="6" left="211.033" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="443.166" width="3.703"/> <word-part bottom="448.4" height="5.312" id="7" left="215.627" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="443.088" width="4.891"/> <debug id="0" message="check for line breaks, diffx: 201.363, diffy: 23.6, diff_conversion_matrix: False"/> </transkription-position> </word> <word deleted="false" id="106" line-number="40" text="und"> <transkription-position bottom="473.797" height="11.11" id="0" left="14.024" top="462.687" width="15.289" writing-process-id="0"> <word-part bottom="472.0" height="5.234" id="0" left="14.174" style-class="st9 st10" symbol-id="glyph4-13" text="u" top="466.766" width="4.859"/> <word-part bottom="472.0" height="5.312" id="1" left="19.528" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="466.688" width="4.891"/> <word-part bottom="472.0" height="7.203" id="2" left="24.882" style-class="st9 st10" symbol-id="glyph4-10" text="d" top="464.797" width="4.281"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="107" line-number="40" text="geschoben,"> <transkription-position bottom="473.719" height="11.11" id="0" left="33.03" top="462.609" width="44.244" writing-process-id="0"> <word-part bottom="472.0" height="7.281" id="0" left="33.18" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="464.719" width="4.203"/> <word-part bottom="472.0" height="5.234" id="1" left="37.774" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="466.766" width="3.703"/> <word-part bottom="472.0" height="5.234" id="2" left="42.368" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="466.766" width="2.938"/> <word-part bottom="472.0" height="5.234" id="3" left="46.042" style-class="st9 st10" symbol-id="glyph4-2" text="c" top="466.766" width="3.531"/> <word-part bottom="472.0" height="7.125" id="4" left="50.456" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="464.875" width="4.891"/> <word-part bottom="472.0" height="5.234" id="5" left="55.81" style-class="st9 st10" symbol-id="glyph4-31" text="o" top="466.766" width="4.062"/> <word-part bottom="472.0" height="7.203" id="6" left="60.774" style-class="st9 st10" symbol-id="glyph4-23" text="b" top="464.797" width="4.281"/> <word-part bottom="472.0" height="5.234" id="7" left="65.738" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="466.766" width="3.703"/> <word-part bottom="472.0" height="5.312" id="8" left="70.332" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="466.688" width="4.891"/> <word-part bottom="472.0" height="3.234" id="9" left="75.686" style-class="st9 st10" symbol-id="glyph4-21" text="," top="468.766" width="1.438"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="108" line-number="40" text="ohne"> <transkription-position bottom="473.875" height="11.11" id="0" left="81.434" top="462.765" width="19.675" writing-process-id="0"> <word-part bottom="472.0" height="5.234" id="0" left="81.584" style-class="st9 st10" symbol-id="glyph4-31" text="o" top="466.766" width="4.062"/> <word-part bottom="472.0" height="7.125" id="1" left="86.548" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="464.875" width="4.891"/> <word-part bottom="472.0" height="5.312" id="2" left="91.902" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="466.688" width="4.891"/> <word-part bottom="472.0" height="5.234" id="3" left="97.256" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="466.766" width="3.703"/> <debug id="0" message="svg/text/tspan/\s"/> </transkription-position> </word> <word deleted="false" id="109" line-number="40" text="Zwangsgefühl."> <transkription-position bottom="473.719" height="11.11" id="0" left="104.844" top="462.609" width="57.672" writing-process-id="0"> <word-part bottom="472.0" height="7.125" id="0" left="104.994" style-class="st9 st10" symbol-id="glyph4-44" text="Z" top="464.875" width="4.875"/> <word-part bottom="472.0" height="5.125" id="1" left="110.338" style-class="st9 st10" symbol-id="glyph4-15" text="w" top="466.875" width="7.562"/> <word-part bottom="472.0" height="5.234" id="2" left="117.902" style-class="st9 st10" symbol-id="glyph4-8" text="a" top="466.766" width="3.812"/> <word-part bottom="472.0" height="5.312" id="3" left="122.316" style-class="st9 st10" symbol-id="glyph4-9" text="n" top="466.688" width="4.891"/> <word-part bottom="472.0" height="7.281" id="4" left="127.67" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="464.719" width="4.203"/> <word-part bottom="472.0" height="5.234" id="5" left="132.264" style-class="st9 st10" symbol-id="glyph4-5" text="s" top="466.766" width="2.938"/> <word-part bottom="472.0" height="7.281" id="6" left="135.938" style-class="st9 st10" symbol-id="glyph4-17" text="g" top="464.719" width="4.203"/> <word-part bottom="472.0" height="5.234" id="7" left="140.532" style-class="st9 st10" symbol-id="glyph4-7" text="e" top="466.766" width="3.703"/> <word-part bottom="472.0" height="7.125" id="8" left="145.126" style-class="st9 st10" symbol-id="glyph4-28" text="f" top="464.875" width="2.766"/> <word-part bottom="472.0" height="6.859" id="9" left="147.87" style-class="st9 st10" symbol-id="glyph4-39" text="ü" top="465.141" width="4.859"/> <word-part bottom="472.0" height="7.125" id="10" left="153.224" style-class="st9 st10" symbol-id="glyph4-3" text="h" top="464.875" width="4.891"/> <word-part bottom="472.0" height="7.125" id="11" left="158.578" style-class="st9 st10" symbol-id="glyph4-24" text="l" top="464.875" width="2.094"/> <word-part bottom="472.0" height="1.25" id="12" left="161.132" style-class="st9 st10" symbol-id="glyph4-19" text="." top="470.75" width="1.234"/> <debug id="0" message="end of loop"/> </transkription-position> </word> <metadata> <type>svgWordPosition</type> <createdBy> <script>/data/home/knister0/nietzsche-python/tests_svgscripts/extractWordPosition.py</script> <date>2019-08-02 15:17:37</date> </createdBy> <modifiedBy script="tests_svgscripts/process_files.py">2019-08-02 15:17:37</modifiedBy> <modifiedBy script="tests_svgscripts/fix_missing_glyphs.py">2019-08-02 15:30:59</modifiedBy> <modifiedBy script="/data/home/knister0/nietzsche-python/tests_svgscripts/process_files.py">2019-08-02 15:30:59</modifiedBy> - <modifiedBy script="svgscripts/join_faksimileAndTranskription.py">2019-11-07 11:44:29</modifiedBy> + <modifiedBy script="svgscripts/join_faksimileAndTranskription.py">2019-11-08 10:36:22</modifiedBy> </metadata> <faksimile-svg file="tests_svgscripts/test_data/faksimile_svg/N-VII-1,5et6.svg"/> <faksimile-image URL="http://www.nietzschesource.org/DFGAapi/api/page/download/N-VII-1,5et6" file-name="N-VII-1,5et6.jpg" height="870.4" local-path="/home/knister0/ownCloud/nietzscheDE/Bearbeitung_Faksimile/Eric/Faksimiles/N-VII-1,5et6.jpg" width="1570.08"> <text-field bottom="762.6" height="661.668" id="N-VII-1_6" left="781.045" top="100.932" width="414.666"/> </faksimile-image> <svg-image file-name="./svg/N_VII_1_page006_web.svg" height="481.891" width="297.637"/> </page> Index: tests_svgscripts/test_line.py =================================================================== --- tests_svgscripts/test_line.py (revision 0) +++ tests_svgscripts/test_line.py (revision 69) @@ -0,0 +1,35 @@ +import unittest +from os import sep, path +from os.path import isdir, dirname +import lxml.etree as ET +import sys +import sys + +sys.path.append('svgscripts') + +from datatypes.line import Line + +class TestLineNumber(unittest.TestCase): + def setUp(self): + DATADIR = dirname(__file__) + sep + 'test_data' + self.test_target_file = DATADIR + sep + 'test.xml' + self.id = 24 + + def test_init(self): + lnr = Line(id=self.id) + self.assertEqual(lnr.id, self.id) + + def test_init_from_xml(self): + xml_tree = ET.parse(self.test_target_file) + lines = [ Line.create_cls_from_node(node=node) for node in xml_tree.getroot().xpath('.//line-number') ] + self.assertEqual(len(lines), 49) + self.assertEqual(lines[0].id, 1) + self.assertEqual(lines[48].id, 49) + + def test_get_semanticAndDataDict(self): + #print(Line.get_semantic_dictionary()) + pass + + +if __name__ == "__main__": + unittest.main() Index: tests_svgscripts/test_faksimile_position.py =================================================================== --- tests_svgscripts/test_faksimile_position.py (revision 0) +++ tests_svgscripts/test_faksimile_position.py (revision 69) @@ -0,0 +1,47 @@ +import unittest +from os import sep, path +import lxml.etree as ET +import sys + +sys.path.append('svgscripts') +from datatypes.faksimile_image import FaksimileImage +from datatypes.matrix import Matrix +from datatypes.word_position import WordPosition +from datatypes.faksimile_position import FaksimilePosition +from datatypes.text_field import TextField + +class TestWordPosition(unittest.TestCase): + def test_init(self): + faksimile_position = FaksimilePosition(id=1, height=10, width=10, x=0, y=10) + self.assertEqual(faksimile_position.id, '1') + self.assertEqual(faksimile_position.height, 10) + self.assertEqual(faksimile_position.top, 10) + self.assertEqual(faksimile_position.bottom, 20) + self.assertEqual(faksimile_position.left, 0) + + def test_attach_object_to_tree(self): + matrix = Matrix('matrix(0 0 0 0 0 0)') + faksimile_position = FaksimilePosition(id=1, height=10, width=10, x=0, y=10, matrix=matrix) + empty_tree = ET.ElementTree(ET.Element('page')) + faksimile_position.attach_object_to_tree(empty_tree) + for node in empty_tree.getroot().xpath('//' + faksimile_position.tag): + self.assertEqual(node.get('id'), '1') + self.assertEqual(node.get('bottom'), '20') + self.assertEqual(node.get('transform'), matrix.toString()) + self.assertEqual(node.get('writing-process-id'), '-1') + faksimile_position = FaksimilePosition(node=empty_tree.getroot().find('.//' + faksimile_position.tag)) + + def test_get_semantic_dictionary(self): + dictionary = FaksimilePosition.get_semantic_dictionary() + #print(dictionary) + + def test_create_list_of_cls(self): + other_list = [ WordPosition(id=1, height=10, width=10, x=0, y=10) ] + faksimile_positions = FaksimilePosition.create_list_of_cls(other_list, FaksimileImage(), TextField()) + self.assertEqual(faksimile_positions[0] != other_list[0], True) + self.assertEqual(type(faksimile_positions[0]), FaksimilePosition) + self.assertEqual(faksimile_positions[0].faksimile_image is not None, True) + self.assertEqual(faksimile_positions[0].text_field is not None, True) + +if __name__ == "__main__": + unittest.main() Index: py2ttl/data_handler.py =================================================================== --- py2ttl/data_handler.py (revision 68) +++ py2ttl/data_handler.py (revision 69) @@ -1,185 +1,176 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ This class can be used to add data to a rdf graph. """ # Copyright (C) University of Basel 2019 {{{1 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/> 1}}} __author__ = "Christian Steiner" __maintainer__ = __author__ __copyright__ = 'University of Basel' __email__ = "christian.steiner@unibas.ch" __status__ = "Development" __license__ = "GPL v3" __version__ = "0.0.1" from rdflib import Graph, URIRef, Literal, BNode, OWL, RDF, RDFS, XSD +from os.path import isfile import random import warnings from class_spec import SemanticClass from config import DATA_URL class RDFDataHandler: """ This class can be used to add data to a rdf graph. """ UNITTESTING = False SIMPLE_DATA_TYPE_MAPPING = { int: XSD.integer, float: XSD.float, str: XSD.string, bool: XSD.boolean, list: RDF.List } def __init__(self, target_file, mapping_dictionary): self.target_file = target_file self.mapping_dictionary = mapping_dictionary + self.ontology_graph = Graph() self.data_graph = Graph() self.data_identifier_mapping = {} if bool(self.mapping_dictionary.get('ontology')): self.project_name = self.mapping_dictionary['ontology'].get('project_name') self.project_uri = URIRef(self.mapping_dictionary['ontology'].get('project_uri')) + ontology_file = self.mapping_dictionary['ontology'].get('ontology_file') + if bool(ontology_file) and isfile(ontology_file): + self.ontology_graph.parse(ontology_file, format="turtle") self.ns = { uriref: ns for ns, uriref in self.data_graph.namespace_manager.namespaces() } self.data_graph.bind(self.project_name, self.project_uri) self.data_graph.bind('data', DATA_URL + '#') else: raise Exception('Error: mapping_dictionary does not contain key "ontology"!') - def add_data(self, data_instance, identifier_prefix, parent_data_instance=None, belongsTopredicate_subject_uri_tuple=None): + def add_data(self, data_instance, identifier_prefix, parent_data_instance=None): """Add a data rdf instance of data_instance to the data_graph. :return: (rdflib.URIRef) subject_uri of data instance """ identifier_uri = self.create_identifier_uri(data_instance, identifier_prefix) - if belongsTopredicate_subject_uri_tuple is not None: - self.data_graph_add((identifier_uri, *belongsTopredicate_subject_uri_tuple)) if bool(self.mapping_dictionary['classes'].get(type(data_instance).__name__)): class_uri = self.mapping_dictionary['classes'][type(data_instance).__name__]['class_uri'] self.data_identifier_mapping.update({data_instance: identifier_uri}) self.data_graph_add((identifier_uri, RDF.type, class_uri)) semantic_dict = data_instance.get_semantic_dictionary() for key, content in semantic_dict['properties'].items(): if bool(self.mapping_dictionary['classes'][type(data_instance).__name__]['properties'].get(key)): - if type(content) is tuple: - datatype, cardinality, xpath = content - elif type(content) is dict and content.get('flag') == 'ordered_list': - datatype = 'ordered_list' - cardinality = content.get('cardinality') - elif type(content) is dict: - datatype = content.get('class') - cardinality = content.get('cardinality') - else: - break + datatype = content.get('class') + cardinality = content.get('cardinality')\ + if bool(content.get('cardinality')) else 0 if data_instance.__dict__.get(key) is not None\ and (type(data_instance.__dict__.get(key)) != int or data_instance.__dict__.get(key) != -1): predicate_uri = self.mapping_dictionary['classes'][type(data_instance).__name__]['properties'][key] child_data_instance = data_instance.__dict__.get(key) - if datatype == 'ordered_list': - new_identifier_prefix = identifier_uri[identifier_uri.index('#')+1:] - self.add_ordered_list(child_data_instance, identifier_uri, predicate_uri, content.get('class'),\ - new_identifier_prefix, parent_data_instance=parent_data_instance) + new_identifier_prefix = identifier_uri[identifier_uri.index('#')+1:] + if datatype is list: + self.add_ordered_list(child_data_instance, identifier_uri, predicate_uri,\ + new_identifier_prefix, data_instance) elif issubclass(datatype, SemanticClass): - new_identifier_prefix = identifier_uri[identifier_uri.index('#')+1:] if type(child_data_instance) is not list: if type(child_data_instance) != datatype: child_id = child_data_instance child_data_instance = parent_data_instance.get_object_from_list_with_id(datatype,\ child_id) if child_data_instance is None: msg = 'No child_data_instance found for data_instance {0}: looking for {1} with id {2}'.format(\ type(parent_data_instance), datatype, child_id) raise Exception(msg) else: new_list_name = 'list_of_' + datatype.__name__ + 's' if new_list_name in data_instance.__dict__.keys(): data_instance.__dict__[new_list_name].append(child_data_instance) else: data_instance.__dict__.update({ new_list_name: [ child_data_instance ]}) if child_data_instance not in self.data_identifier_mapping.keys(): child_identifier_uri = self.add_data(child_data_instance, new_identifier_prefix,\ parent_data_instance=data_instance) else: child_identifier_uri = self.data_identifier_mapping[child_data_instance] self.data_graph_add((identifier_uri, predicate_uri, child_identifier_uri)) else: - belongsTopredicate_subject_uri_tuple = (predicate_uri, identifier_uri)\ - if cardinality == SemanticClass.LIST else None for child_item in child_data_instance: if child_item not in self.data_identifier_mapping.keys(): - child_identifier_uri = self.add_data(child_item, new_identifier_prefix, data_instance,\ - belongsTopredicate_subject_uri_tuple=belongsTopredicate_subject_uri_tuple) + child_identifier_uri = self.add_data(child_item, new_identifier_prefix,\ + parent_data_instance=data_instance) else: child_identifier_uri = self.data_identifier_mapping[child_item] - if belongsTopredicate_subject_uri_tuple is not None\ - and (child_identifier_uri, *belongsTopredicate_subject_uri_tuple) not in self.data_graph: - self.data_graph_add((child_identifier_uri, *belongsTopredicate_subject_uri_tuple)) - if cardinality != SemanticClass.LIST: - self.data_graph_add((identifier_uri, predicate_uri, child_identifier_uri)) + self.data_graph_add((identifier_uri, predicate_uri, child_identifier_uri)) + else: - object_literal = Literal(str(child_data_instance), datatype=RDFDataHandler.SIMPLE_DATA_TYPE_MAPPING[datatype]) + literal_datatype = RDFDataHandler.SIMPLE_DATA_TYPE_MAPPING[datatype] + ontology_datatypes = [ o for o in self.ontology_graph.objects(subject=predicate_uri, predicate=RDFS.range) ] + if len(ontology_datatypes) > 0: + literal_datatype = ontology_datatypes[0] + object_literal = Literal(str(child_data_instance), datatype=literal_datatype) self.data_graph_add((identifier_uri, predicate_uri, object_literal)) else: msg = 'Mapping dictionary for {0} does not contain a entry for {1}!'.format(type(data_instance).__name__, key) raise Exception(msg) else: msg = 'Mapping dictionary does not contain a entry for {}!'.format(type(data_instance).__name__) raise Exception(msg) return identifier_uri - def add_ordered_list(self, data_instance_list, identifier_uri, predicate_uri, class_dict, identifier_prefix, parent_data_instance=None): + def add_ordered_list(self, data_instance_list, identifier_uri, predicate_uri, identifier_prefix, data_instance): """Add a data rdf instance of data_instance to the data_graph. - - :return: (rdflib.URIRef) subject_uri of data instance """ - cls_name = class_dict['class_name'] - if bool(self.mapping_dictionary['classes'].get(cls_name)): - intermediary_class_uri = self.mapping_dictionary['classes'][cls_name]['class_uri'] - intermediary_seqnum_uri = self.mapping_dictionary['classes'][cls_name]['properties'][SemanticClass.HAS_SEQNUM] - intermediary_property_uri = self.mapping_dictionary['classes'][cls_name]['properties'][SemanticClass.HAS_PART] - for index, data_instance in enumerate(data_instance_list): - intermediary_identifier_uri = URIRef(DATA_URL + '#' + identifier_prefix + '_' + cls_name + str(index)) - new_identifier_prefix = intermediary_identifier_uri[intermediary_identifier_uri.index('#')+1:] - child_identifier_uri = self.add_data(data_instance, new_identifier_prefix, parent_data_instance=parent_data_instance) - self.data_graph_add((intermediary_identifier_uri, RDF.type, intermediary_class_uri)) - self.data_graph_add((intermediary_identifier_uri, intermediary_seqnum_uri, Literal(str(index), datatype=RDFDataHandler.SIMPLE_DATA_TYPE_MAPPING[int]))) - self.data_graph_add((intermediary_identifier_uri, intermediary_property_uri, child_identifier_uri)) - self.data_graph_add((identifier_uri, predicate_uri, intermediary_identifier_uri)) - else: - msg = 'Mapping dictionary does not contain a entry for {}!'.format(type(data_instance).__name__) - raise Exception(msg) - return identifier_uri + if len(data_instance_list) > 0: + list_node = BNode() + next_node = None + self.data_graph_add((identifier_uri, predicate_uri, list_node)) + for item in data_instance_list: + if next_node is not None: + self.data_graph_add((list_node, RDF.rest, next_node)) + list_node = next_node + if item not in self.data_identifier_mapping.keys(): + child_identifier_uri = self.add_data(item, identifier_prefix, data_instance) + else: + child_identifier_uri = self.data_identifier_mapping[item] + self.data_graph_add((list_node, RDF.first, child_identifier_uri)) + next_node = BNode() + if next_node is not None: + self.data_graph_add((next_node, RDF.rest, RDF.nil)) def create_identifier_uri(self, data_instance, identifier_prefix): """Return a data identifier uri. :return: (rdflib.URIRef) subject_uri of data instance """ data_type, id = data_instance.get_name_and_id() identifier_uri = URIRef(DATA_URL + '#' + identifier_prefix + '_' + data_type + str(id)) randombit_length = 5 while (identifier_uri, None, None) in self.data_graph: identifier_uri = URIRef(DATA_URL + '#' + identifier_prefix + '_' + data_type + str(random.getrandbits(randombit_length))) randombit_length += 1 return identifier_uri def data_graph_add(self, rdf_triple): """Add a triple to the graph. """ #not RDFDataHandler.UNITTESTING and print(rdf_triple) self.data_graph.add(rdf_triple) def write(self, output_format="turtle"): """Write graph. """ f = open(self.target_file, 'wb+') f.write(self.data_graph.serialize(format=output_format)) f.close() Index: py2ttl/py2ttl_data.py =================================================================== --- py2ttl/py2ttl_data.py (revision 68) +++ py2ttl/py2ttl_data.py (revision 69) @@ -1,138 +1,137 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ This program can be used to convert py objects to data in turtle format. """ # Copyright (C) University of Basel 2019 {{{1 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/> 1}}} from colorama import Fore, Style import getopt import lxml.etree as ET from os import sep, path, listdir from os.path import isfile, isdir, dirname, basename from progress.bar import Bar import re import sys sys.path.append('svgscripts') from datatypes.manuscript import ArchivalManuscriptUnity if dirname(__file__) not in sys.path: sys.path.append(dirname(__file__)) from class_spec import SemanticClass -from config import check_config_files_exist, get_datatypes_dir, PROJECT_NAME, PROJECT_ONTOLOGY_FILE, PROJECT_URL, SHARED_ONTOLOGIES_DIR +from config import check_config_files_exist, get_datatypes_dir, PROJECT_NAME, PROJECT_ONTOLOGY_FILE, PROJECT_URL from data_handler import RDFDataHandler -from knora_base import KNORA_BASE sys.path.append('shared_util') from myxmlwriter import xml2dict __author__ = "Christian Steiner" __maintainer__ = __author__ __copyright__ = 'University of Basel' __email__ = "christian.steiner@unibas.ch" __status__ = "Development" __license__ = "GPL v3" __version__ = "0.0.1" class Py2TTLDataConverter: """This class can be used convert py objects to rdf data in turtle format. """ UNITTESTING = False def __init__(self, manuscript_file, xml_dictionary_file=None, mapping_dictionary=None): if mapping_dictionary is None and xml_dictionary_file is not None: if not Py2TTLDataConverter.UNITTESTING: print(Fore.CYAN + 'initializing mapping dictionary from file "{}" ...'.format(xml_dictionary_file)) self.mapping_dictionary = xml2dict(xml_dictionary_file) if not Py2TTLDataConverter.UNITTESTING: print(Fore.GREEN + '[{} classes added]'.format(str(len(self.mapping_dictionary['classes'])))) elif mapping_dictionary is not None: self.mapping_dictionary = mapping_dictionary else: raise Exception('Error: Py2TTLDataConverter init expects either a xml_dictionary_file or a mapping_dictionary!') self.manuscript_file = manuscript_file def convert(self): """Convert manuscript instantiated with manuscript_file to rdf data and write to target_file. """ not Py2TTLDataConverter.UNITTESTING and print(Fore.CYAN + 'initializing python objects with file "{}" ...'.format(self.manuscript_file)) manuscript = ArchivalManuscriptUnity.create_cls(self.manuscript_file, page_status_list=['OK', 'faksimile merged']) target_data_file = manuscript.title.replace(' ', '_') + '_DATA.ttl' data_handler = RDFDataHandler(target_data_file, self.mapping_dictionary) if not Py2TTLDataConverter.UNITTESTING: print(Fore.GREEN + '[{} pages added]'.format(str(len(manuscript.pages)))) print(Fore.CYAN + 'adding triples to rdf graph ... ') #data_handler.add_data(manuscript, manuscript.title.replace(' ', '_')) data_handler.add_data(manuscript, '') if not Py2TTLDataConverter.UNITTESTING: print(Fore.GREEN + '[{} statements added]'.format(str(len(data_handler.data_graph)))) print(Fore.CYAN + 'writing graph to file "{}" ...'.format(target_data_file)) data_handler.write() if not Py2TTLDataConverter.UNITTESTING: print(Fore.GREEN + '[OK]') print(Style.RESET_ALL) def usage(): """prints information on how to use the script """ print(main.__doc__) def main(argv): """This program can be used to convert py objects to rdf data in turtle format. py2ttl/py2ttl_data.py [OPTIONS] <manuscript.xml> <manuscript.xml> xml file of type shared_util.myxmlwriter.FILE_TYPE_XML_MANUSCRIPT. OPTIONS: -h|--help: show help -m|--mapping=mapping_dict.xml xml file generated by py2ttl/py2ttl.py containing mapping information for each property of a class. :return: exit code (int) """ check_config_files_exist() datatypes_dir = get_datatypes_dir() target_ontology_file = '.{0}{1}-ontology_autogenerated.ttl'.format(sep, PROJECT_NAME) xml_dictionary_file = 'mapping_file4' + datatypes_dir.replace(sep, '.') + '2' + target_ontology_file.replace('.' + sep, '').replace(sep, '.').replace('.ttl', '.xml') manuscript_file = None try: opts, args = getopt.getopt(argv, "hm:", ["help", "mapping="]) except getopt.GetoptError: usage() return 2 for opt, arg in opts: if opt in ('-h', '--help'): usage() return 0 elif opt in ('-m', '--mapping'): xml_dictionary_file = arg if len(args) < 1 : usage() return 2 manuscript_file = args[0] if not isfile(xml_dictionary_file) or not isfile(manuscript_file): usage() return 2 converter = Py2TTLDataConverter(manuscript_file, xml_dictionary_file=xml_dictionary_file) converter.convert() return 0 if __name__ == "__main__": sys.exit(main(sys.argv[1:])) Index: py2ttl/py2ttl_ontology.py =================================================================== --- py2ttl/py2ttl_ontology.py (revision 68) +++ py2ttl/py2ttl_ontology.py (revision 69) @@ -1,353 +1,349 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ This program can be used to convert py classes that are subclasses of class_spec.SemanticClass to a owl ontology in turtle format. """ # Copyright (C) University of Basel 2019 {{{1 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/> 1}}} import getopt import importlib import importlib.util import inspect import lxml.etree as ET from os import sep, path, listdir from os.path import isfile, isdir, dirname, basename from progress.bar import Bar from rdflib import Graph, URIRef, Literal, BNode, OWL, RDF, RDFS, XSD import re import sys import warnings if dirname(__file__) not in sys.path: sys.path.append(dirname(__file__)) from class_spec import SemanticClass, UnSemanticClass from config import check_config_files_exist, get_datatypes_dir, PROJECT_NAME, PROJECT_ONTOLOGY_FILE, PROJECT_URL from data_handler import RDFDataHandler sys.path.append('shared_util') from myxmlwriter import dict2xml __author__ = "Christian Steiner" __maintainer__ = __author__ __copyright__ = 'University of Basel' __email__ = "christian.steiner@unibas.ch" __status__ = "Development" __license__ = "GPL v3" __version__ = "0.0.1" class Py2TTLOntologyConverter: """This class can be used convert semantic_dictionaries to a owl ontology in turtle format. """ UNITTESTING = False def __init__(self, project_ontology_file=None): self.class_uri_dict = {} self.uri_mapping4cls_and_properties = {} self.project_graph = Graph() self.base_uriref = URIRef(PROJECT_URL) self.project_name = PROJECT_NAME self.ns = { self.base_uriref + '#': self.project_name } if project_ontology_file is not None and isfile(project_ontology_file): self.project_graph.parse(project_ontology_file, format="turtle") if len(self.project_graph) > 0: self.base_uriref = self.project_graph.value(predicate=RDF.type, object=OWL.Ontology, any=False) self.ns = { uriref: ns for ns, uriref in self.project_graph.namespace_manager.namespaces() } self.project_name = self.ns.get(self.base_uriref + '#') self.project_graph.bind(self.project_name, self.base_uriref + '#') self.uri_mapping4cls_and_properties.update({ 'ontology': { 'project_name': self.project_name, 'project_uri': self.base_uriref + '#' }}) self.uri_mapping4cls_and_properties.update({ 'classes': {} }) def addClass2Graph(self, cls, semantic_dict=None) -> (URIRef, type): """Add a class to project_graph. :return: (cls_uri (URIRef), super_cls (cls)) """ if semantic_dict is None: semantic_dict = cls.get_semantic_dictionary() comment, label = self.get_comment_label(cls) cls_uri = URIRef(self.base_uriref + '#' + cls.__name__) self.project_graph.add((cls_uri, RDF.type, OWL.Class)) self.project_graph.add((cls_uri, RDFS.isDefinedBy, self.base_uriref)) if comment != '': self.project_graph.add((cls_uri, RDFS.comment, Literal(comment, lang='en'))) if label != '': self.project_graph.add((cls_uri, RDFS.label, Literal(label, lang='en'))) super_uri = None super_cls = None if bool(semantic_dict['class'].get('rdfs:subClassOf')): super_uri = URIRef(semantic_dict['class'].get('rdfs:subClassOf')) if bool(semantic_dict['class'].get('type')): super_cls = semantic_dict['class'].get('type') super_uri = self.createClassAndProperties(super_cls) if super_uri is not None: self.project_graph.add((cls_uri, RDFS.subClassOf, super_uri)) return cls_uri, super_cls def addProperty2Graph(self, property_uri, domain_uri, range_uri, info_dict): """Add a property to self.project_graph. """ label = 'has ' + property_uri.split('#')[1].replace('has','')\ if SemanticClass.PROPERTY_LABEL not in info_dict.keys() else info_dict[SemanticClass.PROPERTY_LABEL] self.project_graph.add((property_uri, RDF.type, OWL.ObjectProperty)) self.project_graph.add((property_uri, RDFS.isDefinedBy, self.base_uriref)) self.project_graph.add((property_uri, RDFS.domain, domain_uri)) self.project_graph.add((property_uri, RDFS.range, range_uri)) if SemanticClass.PROPERTY_COMMENT in info_dict.keys(): comment = info_dict[SemanticClass.PROPERTY_COMMENT] self.project_graph.add((property_uri, RDFS.comment, Literal(comment, lang='en'))) self.project_graph.add((property_uri, RDFS.label, Literal(label, lang='en'))) if SemanticClass.CARDINALITY in info_dict.keys()\ and info_dict[SemanticClass.CARDINALITY] > 0: self.addRestriction2Class(domain_uri, property_uri, info_dict) def addRestriction2Class(self, cls_uri, property_uri, info_dict): """Adds restriction on property_uri to class cls_uri. """ if SemanticClass.CARDINALITY in info_dict.keys()\ and info_dict[SemanticClass.CARDINALITY] > 0: if (cls_uri, None, None) not in self.project_graph: warnings.warn('{} not in graph!'.format(cls_uri)) restriction = BNode() cardinality_restriction = URIRef(OWL + info_dict[SemanticClass.CARDINALITY_RESTRICTION])\ if SemanticClass.CARDINALITY_RESTRICTION in info_dict.keys()\ else OWL.cardinality cardinality = info_dict[SemanticClass.CARDINALITY] self.project_graph.add((cls_uri, RDFS.subClassOf, restriction)) self.project_graph.add((restriction, RDF.type, OWL.Restriction)) self.project_graph.add((restriction, OWL.onProperty, property_uri)) self.project_graph.add((restriction, cardinality_restriction, Literal(str(cardinality), datatype=XSD.nonNegativeInteger))) def convert_py2ttl(self, datatypes_dir, target_ontology_file): """Convert all classes contained in datatypes_dir that are subclasses of class_spec.SemanticClass to rdf. :return: exit code (int) """ if isdir(datatypes_dir): semantic_classes = self.get_semantic_classes(datatypes_dir) if not Py2TTLOntologyConverter.UNITTESTING: bar = Bar('creating classes and properties', max=len(semantic_classes)) for cls in semantic_classes: self.createClassAndProperties(cls) not bool(Py2TTLOntologyConverter.UNITTESTING) and bar.next() not bool(Py2TTLOntologyConverter.UNITTESTING) and bar.finish() + self.uri_mapping4cls_and_properties['ontology'].update({'ontology_file': target_ontology_file}) f = open(target_ontology_file, 'wb+') f.write(self.project_graph.serialize(format="turtle")) f.close() if not Py2TTLOntologyConverter.UNITTESTING: xml_file = 'mapping_file4' + datatypes_dir.replace(sep, '.') + '2' + target_ontology_file.replace('.' + sep, '').replace(sep, '.').replace('.ttl', '.xml') dict2xml(self.uri_mapping4cls_and_properties, xml_file) else: print('Error: dir {} does not exist!'.format(datatypes_dir)) usage return 1 return 0 def createClassAndProperties(self, cls): """Creates a owl:Class and some owl:ObjectProperty from semantic_dictionary of a python class. """ if not cls.__name__ in self.class_uri_dict: self.class_uri_dict.update({cls.__name__: cls}) semantic_dict = cls.get_semantic_dictionary() cls_uri, super_cls = self.addClass2Graph(cls, semantic_dict) uri_mapping4properties = {} for property_key in self._get_semantic_dictionary_keys_super_first(semantic_dict['properties']): super_semantic_dict = {} if super_cls is None else super_cls.get_semantic_dictionary() if len(super_semantic_dict) == 0 or not bool(super_semantic_dict['properties'].get(property_key)): property_dict4key = semantic_dict['properties'].get(property_key) property_cls = property_dict4key.get('class') subject_uri, property_uri = self.createProperty(cls_uri, property_key, property_cls, property_dict4key) uri_mapping4properties.update({ property_key: property_uri }) elif bool(self.uri_mapping4cls_and_properties.get('classes').get(super_cls.__name__).get('properties').get(property_key)): property_uri = self.uri_mapping4cls_and_properties['classes'][super_cls.__name__]['properties'][property_key] uri_mapping4properties.update({ property_key: property_uri}) self.uri_mapping4cls_and_properties.get('classes').update({ cls.__name__: { 'class_uri': cls_uri, 'properties': uri_mapping4properties }}) return URIRef(self.base_uriref + '#' + cls.__name__) def createProperty(self, domain_uri, property_name, range_cls, info_dict) -> (URIRef, URIRef): """Creates a owl:ObjectProperty. :return: tuple of domain_uri (rdflib.URIRef) and property_uri (rdflib.URIRef) of created property """ name = self.createPropertyName(property_name=property_name)\ if SemanticClass.PROPERTY_NAME not in info_dict.keys() else info_dict[SemanticClass.PROPERTY_NAME] property_uri = URIRef(self.base_uriref + '#' + name) inferredSubClass = RDFS.subClassOf * '*' range_uri = URIRef(self.base_uriref + '#' + range_cls.__name__) if (property_uri, None, None) not in self.project_graph: if range_cls.__module__ == 'builtins': range_uri = RDFDataHandler.SIMPLE_DATA_TYPE_MAPPING.get(range_cls) if range_uri == XSD.string and property_name == 'URL': range_uri = XSD.anyURI self.addProperty2Graph(property_uri, domain_uri, range_uri, info_dict) elif not True in [\ (domain_uri, inferredSubClass, o) in self.project_graph\ for o in self.project_graph.objects(property_uri, RDFS.domain)\ ]: # if domain_uri is NOT a subclass of a cls specified by RDFS.domain if SemanticClass.CARDINALITY in info_dict.keys()\ and info_dict[SemanticClass.CARDINALITY] > 0: self.addRestriction2Class(domain_uri, property_uri, info_dict) self.project_graph.add((property_uri, RDFS.domain, domain_uri)) return domain_uri, property_uri def createPropertyName(self, property_name=None, subject_uri=None, object_uri=None, connector='BelongsTo', prefix='has'): """Returns a property name. """ if property_name is not None: property_name = ''.join([ property_name.split('_')[0].lower() ] + [ text.capitalize() for text in property_name.split('_')[1:] ]) return prefix + property_name[0].upper() + property_name[1:] if property_name[0].islower()\ else prefix + property_name elif subject_uri is not None: property_name = subject_uri.split('#')[1] + self.createPropertyName(object_uri=object_uri, prefix=connector) return property_name[0].lower() + property_name[1:] elif object_uri is not None: return prefix + object_uri.split('#')[1] else: return prefix def get_comment_label(self, cls): """Returns comment and label from cls __doc__. """ comment = cls.__doc__.replace('\n','').lstrip() label = cls.__name__ if '.' in cls.__doc__: comment = [ text for text in cls.__doc__.split('\n') if text != '' ][0].lstrip() if '@label' in cls.__doc__: m = re.search('(@label[:]*\s)(.*[\.]*)', cls.__doc__) label_tag, label = m.groups() elif re.search('([A-Z][a-z]+)', label): m = re.search('([A-Z]\w+)([A-Z]\w+)', label) label = ' '.join([ text.lower() for text in re.split(r'([A-Z][a-z]+)', label) if text != '' ]) return comment, label def get_semantic_classes(self, datatypes_dir): """Returns a list of all classes that are contained in datatypes_dir that are subclasses of class_spec.SemanticClass. :return: a list of (str_name, class) """ base_dir = dirname(dirname(__file__)) sys.path.append(base_dir) root_modul_name = datatypes_dir.replace('/','.') files = [ file.replace('.py','') for file in listdir(datatypes_dir) if file.endswith('.py') and not file.startswith('test_') and not file.startswith('_')] all_modules = [] for name in files: all_modules.append(importlib.import_module('{}.{}'.format(root_modul_name, name))) all_classes = [] for modul in all_modules: all_classes += inspect.getmembers(modul, inspect.isclass) all_classes = sorted(set(all_classes)) semantic_classes = [ cls for name, cls in all_classes if issubclass(cls, SemanticClass)\ and not issubclass(cls, UnSemanticClass)\ and not (cls == SemanticClass)] return semantic_classes def _get_builtin_cls_keys(self, property_dict): """Returns a list of keys for classes that are builtin. """ builtin_cls_keys = [] for key in property_dict.keys(): property_cls = property_dict.get(key).get('class')\ if type(property_dict.get(key)) is dict\ else property_dict.get(key)[0] if type(property_cls) != dict\ and property_cls.__module__ == 'builtins': builtin_cls_keys.append(key) return builtin_cls_keys def _get_semantic_dictionary_keys_super_first(self, property_dict): """Sorts the keys of the property part of a semantic dictionary and returns the keys for super classes before keys of subclasses. :return: a sorted list of keys. """ builtin_cls_keys = self._get_builtin_cls_keys(property_dict) complex_cls_keys = [] for key in [ key for key in property_dict.keys()\ if key not in builtin_cls_keys ]: current_cls = property_dict.get(key).get('class') key_inserted = False for index, cls_key in enumerate(complex_cls_keys): potential_sub_cls = property_dict.get(cls_key).get('class') if issubclass(potential_sub_cls, current_cls): complex_cls_keys.insert(index, key) key_inserted = True break if not key_inserted: complex_cls_keys.append(key) return builtin_cls_keys + complex_cls_keys - def write_mapping_file(self, datatypes_dir, target_ontology_file): - """Write a mapping xml file for each semantic class. - """ - pass - def create_dummy_cls(class_name): """Return a dummy class for class_name (str). """ exec('class %s:pass' % class_name) return eval('%s' % class_name) def usage(): """prints information on how to use the script """ print(main.__doc__) def main(argv): """This program can be used to convert py classes that are subclasses of class_spec.SemanticClass to owl:Class. py2ttl/py2ttl_ontology.py [OPTIONS <dir>] <dir> [optional] directory containing datatypes that are subclasses of class_spec.SemanticClass. Overwrites DATATYPES_DIR in py2ttl/config.py. OPTIONS: -h|--help: show help -s|--source=source_ontology_file source ontology ttl file, option overwrites PROJECT_ONTOLOGY_FILE in py2ttl/config.py -t|--target=target_ontology_file target ontology ttl file, default: 'PROJECT_PREFIX-ontology_autogenerated.ttl' :return: exit code (int) """ check_config_files_exist() datatypes_dir = get_datatypes_dir() source_ontology_file = PROJECT_ONTOLOGY_FILE target_ontology_file = '' try: opts, args = getopt.getopt(argv, "hs:t:", ["help","source=", "target="]) except getopt.GetoptError: usage() return 2 for opt, arg in opts: if opt in ('-h', '--help'): usage() return 0 elif opt in ('-t', '--target'): target_ontology_file = arg elif opt in ('-s', '--source'): source_ontology_file = arg converter = Py2TTLOntologyConverter(project_ontology_file=source_ontology_file) if len(args) > 0: datatypes_dir = args[0] if target_ontology_file == '': target_ontology_file = '.{0}{1}-ontology_autogenerated.ttl'.format(sep, converter.project_name) return converter.convert_py2ttl(datatypes_dir, target_ontology_file) if __name__ == "__main__": sys.exit(main(sys.argv[1:]))