GEPS 011: Tagging - Add XML import and export

svn: r15938
This commit is contained in:
Nick Hall 2010-09-29 22:25:52 +00:00
parent 8b675ed1f2
commit 6b6da7dafe
6 changed files with 364 additions and 160 deletions

View File

@ -24,45 +24,46 @@
-->
<!--
This is the Document Type Definition file for v1.3.0
This is the Document Type Definition file for v1.4.0
of the GRAMPS XML genealogy data format.
Please use the following formal public identifier to identify it:
"-//GRAMPS//DTD GRAMPS XML V1.3.0//EN"
"-//GRAMPS//DTD GRAMPS XML V1.4.0//EN"
For example:
<!DOCTYPE database PUBLIC "-//GRAMPS//DTD GRAMPS XML V1.3.0//EN"
"http://gramps-project.org/xml/1.3.0/grampsxml.dtd"
<!DOCTYPE database PUBLIC "-//GRAMPS//DTD GRAMPS XML V1.4.0//EN"
"http://gramps-project.org/xml/1.4.0/grampsxml.dtd"
[...]>
-->
<!--
DATABASE
Defines an XML document which is a <database> consisting of a
Defines an XML document which is a <database> consisting of a
header Information about the "owner" of the database
people
families
sources
places
objects
repositories
notes
bookmarks
header Information about the "owner" of the database
people
families
sources
places
objects
repositories
notes
tags
bookmarks
-->
<!ELEMENT database (header, name-formats?, events?, people?, families?,
<!ELEMENT database (header, name-formats?, tags?, events?, people?, families?,
sources?, places?, objects?, repositories?, notes?,
bookmarks?,namemaps?)>
<!ATTLIST database xmlns CDATA #FIXED "http://gramps-project.org/xml/1.3.0/">
bookmarks?, namemaps?)>
<!ATTLIST database xmlns CDATA #FIXED "http://gramps-project.org/xml/1.4.0/">
<!-- ************************************************************
<!-- ************************************************************
HEADER
A <header> consists of <created> (information about this
genealogical database) and <researcher> (information about the
person who created this genealogical database)
A <header> consists of <created> (information about this
genealogical database) and <researcher> (information about the
person who created this genealogical database)
-->
<!ELEMENT header (created, researcher?, mediapath?)>
@ -86,7 +87,7 @@ HEADER
<!ELEMENT mediapath (#PCDATA)>
<!-- ************************************************************
<!-- ************************************************************
PEOPLE
-->
@ -98,12 +99,12 @@ PEOPLE
<!ELEMENT person (gender, name*, nick?, eventref*, lds_ord*,
objref*, address*, attribute*, url*, childof*,
parentin*, personref*, noteref*, sourceref*)>
parentin*, personref*, noteref*, sourceref*, tagref*)>
<!ATTLIST person
id CDATA #REQUIRED
handle ID #REQUIRED
priv (0|1) #IMPLIED
marker CDATA #IMPLIED
marker CDATA #IMPLIED
change CDATA #REQUIRED
>
@ -112,8 +113,8 @@ GENDER has values of M, F, or U.
-->
<!ELEMENT gender (#PCDATA)>
<!ELEMENT name (first?,call?,last?,suffix?,patronymic?,title?,
(daterange|datespan|dateval|datestr)?,noteref*,sourceref*)>
<!ELEMENT name (first?, call?, last?, suffix?, patronymic?, title?,
(daterange|datespan|dateval|datestr)?, noteref*, sourceref*)>
<!ATTLIST name
alt (0|1) #IMPLIED
type CDATA #IMPLIED
@ -133,7 +134,7 @@ GENDER has values of M, F, or U.
<!ELEMENT patronymic (#PCDATA)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT nick (#PCDATA)>
<!ELEMENT nick (#PCDATA)>
<!ELEMENT childof EMPTY>
<!ATTLIST childof hlink IDREF #REQUIRED
@ -142,15 +143,16 @@ GENDER has values of M, F, or U.
<!ELEMENT parentin EMPTY>
<!ATTLIST parentin hlink IDREF #REQUIRED>
<!ELEMENT personref (sourceref*,noteref*)>
<!ELEMENT personref (sourceref*, noteref*)>
<!ATTLIST personref
hlink IDREF #REQUIRED
priv (0|1) #IMPLIED
rel CDATA #REQUIRED
hlink IDREF #REQUIRED
priv (0|1) #IMPLIED
rel CDATA #REQUIRED
>
<!ELEMENT address ((daterange|datespan|dateval|datestr)?,street?,city?,
county?,state?,country?,postal?,phone?,noteref*,sourceref*)>
<!ELEMENT address ((daterange|datespan|dateval|datestr)?, street?, city?,
county?, state?, country?, postal?, phone?, noteref*,
sourceref*)>
<!ATTLIST address priv (0|1) #IMPLIED>
<!ELEMENT street (#PCDATA)>
@ -162,20 +164,20 @@ GENDER has values of M, F, or U.
<!ELEMENT phone (#PCDATA)>
<!-- ************************************************************
<!-- ************************************************************
FAMILY
An element to record information about a family.
An element to record information about a family.
-->
<!ELEMENT families (family)*>
<!ELEMENT family (rel?,father?,mother?,eventref*,lds_ord*,
objref*,childref*,attribute*,noteref*,sourceref*)>
<!ELEMENT family (rel?, father?, mother?, eventref*, lds_ord*,
objref*, childref*, attribute*, noteref*, sourceref*)>
<!ATTLIST family
id CDATA #REQUIRED
handle ID #REQUIRED
priv (0|1) #IMPLIED
marker CDATA #IMPLIED
marker CDATA #IMPLIED
change CDATA #REQUIRED
>
@ -187,10 +189,10 @@ FAMILY
<!ELEMENT childref (sourceref*,noteref*)>
<!ATTLIST childref
hlink IDREF #REQUIRED
priv (0|1) #IMPLIED
mrel (None|Birth|Adopted|Stepchild|Sponsored|Foster|Other|Unknown) #IMPLIED
frel (None|Birth|Adopted|Stepchild|Sponsored|Foster|Other|Unknown) #IMPLIED
hlink IDREF #REQUIRED
priv (0|1) #IMPLIED
mrel (None|Birth|Adopted|Stepchild|Sponsored|Foster|Other|Unknown) #IMPLIED
frel (None|Birth|Adopted|Stepchild|Sponsored|Foster|Other|Unknown) #IMPLIED
>
<!ELEMENT type (#PCDATA)>
@ -198,33 +200,33 @@ FAMILY
<!ELEMENT rel EMPTY>
<!ATTLIST rel type CDATA #REQUIRED>
<!-- ************************************************************
<!-- ************************************************************
EVENT
-->
<!ELEMENT events (event)*>
<!ELEMENT event (type?,(daterange|datespan|dateval|datestr)?,place?,cause?,
description?,attribute*,noteref*,sourceref*,objref*)>
<!ELEMENT event (type?, (daterange|datespan|dateval|datestr)?, place?, cause?,
description?, attribute*, noteref*, sourceref*, objref*)>
<!ATTLIST event
id CDATA #REQUIRED
handle ID #REQUIRED
priv (0|1) #IMPLIED
marker CDATA #IMPLIED
marker CDATA #IMPLIED
change CDATA #REQUIRED
>
<!-- ************************************************************
<!-- ************************************************************
SOURCES
-->
<!ELEMENT sources (source)*>
<!ELEMENT source (stitle?,sauthor?,spubinfo?,sabbrev?,
noteref*,objref*,data_item*,reporef*)>
<!ELEMENT source (stitle?, sauthor?, spubinfo?, sabbrev?,
noteref*, objref*, data_item*, reporef*)>
<!ATTLIST source
id CDATA #REQUIRED
handle ID #REQUIRED
priv (0|1) #IMPLIED
marker CDATA #IMPLIED
marker CDATA #IMPLIED
change CDATA #REQUIRED
>
<!ELEMENT stitle (#PCDATA)>
@ -232,22 +234,23 @@ SOURCES
<!ELEMENT spubinfo (#PCDATA)>
<!ELEMENT sabbrev (#PCDATA)>
<!-- ************************************************************
<!-- ************************************************************
PLACES
-->
<!ELEMENT places (placeobj)*>
<!ELEMENT placeobj (ptitle?,coord?,location*,objref*,url*,noteref*,sourceref*)>
<!ELEMENT placeobj (ptitle?, coord?, location*, objref*, url*, noteref*,
sourceref*)>
<!ATTLIST placeobj
id CDATA #REQUIRED
handle ID #REQUIRED
priv (0|1) #IMPLIED
marker CDATA #IMPLIED
marker CDATA #IMPLIED
change CDATA #REQUIRED
>
<!ELEMENT ptitle (#PCDATA)>
<!ELEMENT ptitle (#PCDATA)>
<!ELEMENT coord EMPTY>
<!ATTLIST coord
@ -257,29 +260,29 @@ PLACES
<!ELEMENT location EMPTY>
<!ATTLIST location
street CDATA #IMPLIED
city CDATA #IMPLIED
parish CDATA #IMPLIED
county CDATA #IMPLIED
state CDATA #IMPLIED
country CDATA #IMPLIED
postal CDATA #IMPLIED
phone CDATA #IMPLIED
street CDATA #IMPLIED
city CDATA #IMPLIED
parish CDATA #IMPLIED
county CDATA #IMPLIED
state CDATA #IMPLIED
country CDATA #IMPLIED
postal CDATA #IMPLIED
phone CDATA #IMPLIED
>
<!-- ************************************************************
<!-- ************************************************************
OBJECTS
-->
<!ELEMENT objects (object)*>
<!ELEMENT object (file,attribute*,noteref*,
(daterange|datespan|dateval|datestr)?,sourceref*)>
<!ELEMENT object (file, attribute*, noteref*,
(daterange|datespan|dateval|datestr)?, sourceref*)>
<!ATTLIST object
id CDATA #REQUIRED
handle ID #REQUIRED
priv (0|1) #IMPLIED
marker CDATA #IMPLIED
marker CDATA #IMPLIED
change CDATA #REQUIRED
>
@ -290,56 +293,71 @@ OBJECTS
description CDATA #REQUIRED
>
<!-- ************************************************************
<!-- ************************************************************
REPOSITORIES
-->
<!ELEMENT repositories (repository)*>
<!ELEMENT repository (rname,type,address*,url*,noteref*)>
<!ELEMENT repository (rname, type, address*, url*, noteref*)>
<!ATTLIST repository
id CDATA #REQUIRED
handle ID #REQUIRED
priv (0|1) #IMPLIED
marker CDATA #IMPLIED
marker CDATA #IMPLIED
change CDATA #REQUIRED
>
<!ELEMENT rname (#PCDATA)>
<!-- ************************************************************
<!-- ************************************************************
NOTES
-->
<!ELEMENT notes (note)*>
<!ELEMENT note (text,tag*)>
<!ELEMENT note (text, style*)>
<!ATTLIST note
id CDATA #REQUIRED
handle ID #REQUIRED
priv (0|1) #IMPLIED
marker CDATA #IMPLIED
change CDATA #REQUIRED
format (0|1) #IMPLIED
type CDATA #REQUIRED
marker CDATA #IMPLIED
change CDATA #REQUIRED
format (0|1) #IMPLIED
type CDATA #REQUIRED
>
<!ELEMENT text (#PCDATA)>
<!ELEMENT tag (range+)>
<!ATTLIST tag
name (bold|italic|underline|fontface|fontsize|
fontcolor|highlight|superscript) #REQUIRED
value CDATA #IMPLIED
<!ELEMENT style (range+)>
<!ATTLIST style
name (bold|italic|underline|fontface|fontsize|
fontcolor|highlight|superscript) #REQUIRED
value CDATA #IMPLIED
>
<!ELEMENT range EMPTY>
<!ATTLIST range
start CDATA #REQUIRED
end CDATA #REQUIRED
start CDATA #REQUIRED
end CDATA #REQUIRED
>
<!-- ************************************************************
<!-- ************************************************************
TAGS
-->
<!ELEMENT tags (tag)*>
<!ELEMENT tag EMPTY>
<!ATTLIST tag
handle ID #REQUIRED
name CDATA #REQUIRED
color CDATA #REQUIRED
priority CDATA #REQUIRED
change CDATA #REQUIRED
>
<!-- ************************************************************
BOOKMARKS
-->
@ -350,7 +368,7 @@ BOOKMARKS
hlink IDREF #REQUIRED
>
<!-- ************************************************************
<!-- ************************************************************
NAME MAPS
-->
<!ELEMENT namemaps (map)*>
@ -361,7 +379,7 @@ NAME MAPS
value CDATA #REQUIRED
>
<!-- ************************************************************
<!-- ************************************************************
NAME FORMATS
-->
@ -374,10 +392,10 @@ NAME FORMATS
active (0|1) #IMPLIED
>
<!-- ************************************************************
<!-- ************************************************************
SHARED ELEMENTS
-->
<!ELEMENT daterange EMPTY>
<!ELEMENT daterange EMPTY>
<!ATTLIST daterange
start CDATA #REQUIRED
stop CDATA #REQUIRED
@ -387,17 +405,17 @@ SHARED ELEMENTS
newyear CDATA #IMPLIED
>
<!ELEMENT datespan EMPTY>
<!ELEMENT datespan EMPTY>
<!ATTLIST datespan
start CDATA #REQUIRED
stop CDATA #REQUIRED
quality (estimated|calculated) #IMPLIED
cformat CDATA #IMPLIED
start CDATA #REQUIRED
stop CDATA #REQUIRED
quality (estimated|calculated) #IMPLIED
cformat CDATA #IMPLIED
dualdated (0|1) #IMPLIED
newyear CDATA #IMPLIED
>
<!ELEMENT dateval EMPTY>
<!ELEMENT dateval EMPTY>
<!ATTLIST dateval
val CDATA #REQUIRED
type (before|after|about) #IMPLIED
@ -407,17 +425,17 @@ SHARED ELEMENTS
newyear CDATA #IMPLIED
>
<!ELEMENT datestr EMPTY>
<!ELEMENT datestr EMPTY>
<!ATTLIST datestr val CDATA #REQUIRED>
<!ELEMENT sourceref (spage?,noteref*,(daterange|datespan|dateval|datestr)?)>
<!ELEMENT sourceref (spage? ,noteref*, (daterange|datespan|dateval|datestr)?)>
<!ATTLIST sourceref
hlink IDREF #REQUIRED
priv (0|1) #IMPLIED
conf CDATA #IMPLIED
>
<!ELEMENT eventref (attribute*,noteref*)>
<!ELEMENT eventref (attribute*, noteref*)>
<!ATTLIST eventref
hlink IDREF #REQUIRED
priv (0|1) #IMPLIED
@ -437,13 +455,18 @@ SHARED ELEMENTS
hlink IDREF #REQUIRED
>
<!ELEMENT spage (#PCDATA)>
<!ELEMENT tagref EMPTY>
<!ATTLIST tagref
hlink IDREF #REQUIRED
>
<!ELEMENT attribute (sourceref*,noteref*)>
<!ELEMENT spage (#PCDATA)>
<!ELEMENT attribute (sourceref*, noteref*)>
<!ATTLIST attribute
priv (0|1) #IMPLIED
type CDATA #REQUIRED
value CDATA #REQUIRED
priv (0|1) #IMPLIED
type CDATA #REQUIRED
value CDATA #REQUIRED
>
<!ELEMENT place EMPTY>
@ -454,13 +477,13 @@ SHARED ELEMENTS
<!ELEMENT url EMPTY>
<!ATTLIST url
priv (0|1) #IMPLIED
type CDATA #IMPLIED
href CDATA #REQUIRED
priv (0|1) #IMPLIED
type CDATA #IMPLIED
href CDATA #REQUIRED
description CDATA #IMPLIED
>
<!ELEMENT objref (region?,attribute*,sourceref*,noteref*)>
<!ELEMENT objref (region?, attribute*, sourceref*, noteref*)>
<!ATTLIST objref
hlink IDREF #REQUIRED
priv (0|1) #IMPLIED
@ -480,10 +503,10 @@ SHARED ELEMENTS
value CDATA #REQUIRED
>
<!ELEMENT lds_ord ((daterange|datespan|dateval|datestr)?,temple?,place?,
status?,sealed_to?,noteref*,sourceref*)>
<!ELEMENT lds_ord ((daterange|datespan|dateval|datestr)?, temple?, place?,
status?, sealed_to?, noteref*, sourceref*)>
<!ATTLIST lds_ord
priv (0|1) #IMPLIED
priv (0|1) #IMPLIED
type CDATA #REQUIRED
>

View File

@ -31,7 +31,7 @@
<grammar
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
ns="http://gramps-project.org/xml/1.3.0/"
ns="http://gramps-project.org/xml/1.4.0/"
xmlns="http://relaxng.org/ns/structure/1.0">
<start><element name="database">
@ -53,6 +53,12 @@
</element></zeroOrMore>
</element></optional>
<optional><element name="tags">
<zeroOrMore><element name="tag">
<ref name="tag-content"/>
</element></zeroOrMore>
</element></optional>
<optional><element name="events">
<zeroOrMore><element name="event">
<ref name="event-content"/>
@ -129,15 +135,19 @@
<optional><element name="resemail"><text/></element></optional>
</define>
<define name="primary-object">
<attribute name="id"><text/></attribute>
<define name="table-object">
<attribute name="handle"><data type="ID"/></attribute>
<attribute name="change"><text/></attribute>
</define>
<define name="primary-object">
<ref name="table-object"/>
<attribute name="id"><text/></attribute>
<optional><attribute name="priv"><choice>
<value>0</value>
<value>1</value>
</choice></attribute></optional>
<optional><attribute name="marker"><text/></attribute></optional>
<attribute name="change"><text/></attribute>
</define>
<define name="person-content">
@ -188,6 +198,9 @@
<zeroOrMore><element name="sourceref">
<ref name="sourceref-content"/>
</element></zeroOrMore>
<zeroOrMore><element name="tagref">
<ref name="tagref-content"/>
</element></zeroOrMore>
</define>
<define name="child-rel">
@ -268,10 +281,10 @@
<value>calculated</value>
</choice></attribute></optional>
<optional><attribute name="cformat"><text/></attribute></optional>
<optional><attribute name="dualdated">
<optional><attribute name="dualdated">
<choice><value>0</value><value>1</value></choice>
</attribute></optional>
<optional><attribute name="newyear"><text/></attribute></optional>
</attribute></optional>
<optional><attribute name="newyear"><text/></attribute></optional>
</element>
<element name="datespan">
<attribute name="start"><text/></attribute>
@ -281,10 +294,10 @@
<value>calculated</value>
</choice></attribute></optional>
<optional><attribute name="cformat"><text/></attribute></optional>
<optional><attribute name="dualdated">
<optional><attribute name="dualdated">
<choice><value>0</value><value>1</value></choice>
</attribute></optional>
<optional><attribute name="newyear"><text/></attribute></optional>
</attribute></optional>
<optional><attribute name="newyear"><text/></attribute></optional>
</element>
<element name="dateval">
<attribute name="val"><text/></attribute>
@ -298,10 +311,10 @@
<value>estimated</value>
<value>calculated</value>
</choice></attribute></optional>
<optional><attribute name="dualdated">
<optional><attribute name="dualdated">
<choice><value>0</value><value>1</value></choice>
</attribute></optional>
<optional><attribute name="newyear"><text/></attribute></optional>
</attribute></optional>
<optional><attribute name="newyear"><text/></attribute></optional>
</element>
<element name="datestr">
<attribute name="val"><text/></attribute>
@ -504,7 +517,7 @@
<define name="styledtext">
<element name="text"><text/></element>
<zeroOrMore><element name="tag">
<zeroOrMore><element name="style">
<attribute name="name"><choice>
<value>bold</value>
<value>italic</value>
@ -650,4 +663,15 @@
<text/>
</define>
<define name="tagref-content">
<attribute name="hlink"><data type="IDREF"/></attribute>
</define>
<define name="tag-content">
<ref name="table-object"/>
<attribute name="name"><text/></attribute>
<attribute name="color"><text/></attribute>
<attribute name="priority"><data type="integer"/></attribute>
</define>
</grammar>

View File

@ -198,9 +198,10 @@ class GrampsXmlWriter(UpdateCallback):
repo_len = self.db.get_number_of_repositories()
obj_len = self.db.get_number_of_media_objects()
note_len = self.db.get_number_of_notes()
tag_len = self.db.get_number_of_tags()
total_steps = person_len + family_len + event_len + source_len \
+ place_len + repo_len + obj_len + note_len
+ place_len + repo_len + obj_len + note_len + tag_len
self.set_total(total_steps)
@ -233,6 +234,16 @@ class GrampsXmlWriter(UpdateCallback):
# by the time we get to person's names
self.write_name_formats()
# Write table objects
if tag_len > 0:
self.g.write(" <tags>\n")
for key in self.db.get_tag_handles():
tag = self.db.get_tag_from_handle(key)
self.write_tag(tag, 2)
self.update()
self.g.write(" </tags>\n")
# Write primary objects
if event_len > 0:
self.g.write(" <events>\n")
for handle in self.db.get_event_handles():
@ -384,6 +395,19 @@ class GrampsXmlWriter(UpdateCallback):
escxml(name), escxml(fmt_str), int(active)) )
self.g.write(" </name-formats>\n")
def write_tag(self, tag, index=2):
"""
Write a tag definition.
"""
if not tag:
return
self.write_table_tag('tag', tag, index, close=False)
self.g.write(' name="%s"' % escxml(tag.get_name()))
self.g.write(' color="%s"' % tag.get_color())
self.g.write(' priority="%d"' % tag.get_priority())
self.g.write('/>\n')
def fix(self,line):
try:
l = unicode(line)
@ -426,7 +450,7 @@ class GrampsXmlWriter(UpdateCallback):
name = tag.name.xml_str()
value = tag.value
self.g.write(' ' * index + '<tag name="%s"' % name)
self.g.write(' ' * index + '<style name="%s"' % name)
if value:
self.g.write(' value="%s"' % escxml(str(value)))
self.g.write('>\n')
@ -435,7 +459,7 @@ class GrampsXmlWriter(UpdateCallback):
self.g.write((' ' * (index + 1)) +
'<range start="%d" end="%d"/>\n' % (start, end))
self.g.write(' ' * index + '</tag>\n')
self.g.write(' ' * index + '</style>\n')
def write_text(self, val, text, indent=0):
if not text:
@ -488,6 +512,10 @@ class GrampsXmlWriter(UpdateCallback):
for s in person.get_source_references():
self.dump_source_ref(s,index+2)
for tag_handle in person.get_tag_list():
self.write_ref("tagref", tag_handle, index+1)
self.g.write("%s</person>\n" % sp)
def write_family(self,family,index=1):
@ -711,22 +739,37 @@ class GrampsXmlWriter(UpdateCallback):
self.g.write('%s<%s hlink="_%s"%s%s>\n'
% (sp,tagname, handle,extra_text,close_tag))
def write_primary_tag(self,tagname, obj,index=1,close=True):
def write_primary_tag(self, tagname, obj, index=1, close=True):
"""
Write the tag attributes common to all primary objects.
"""
if not obj:
return
sp = " "*index
marker = obj.get_marker().xml_str()
if marker:
marker_text = ' marker="%s"' % escxml(marker)
else:
marker_text = ''
priv_text = conf_priv(obj)
change_text = ' change="%d"' % obj.get_change_time()
handle_id_text = ' id="%s" handle="_%s"' % (escxml(obj.gramps_id), obj.handle)
obj_text = '%s<%s' % (sp,tagname)
id_text = ' id="%s"' % escxml(obj.gramps_id)
self.g.write(obj_text + handle_id_text + priv_text + marker_text +
change_text)
self.write_table_tag(tagname, obj, index, False)
self.g.write(id_text + priv_text + marker_text)
if close:
self.g.write('>\n')
def write_table_tag(self, tagname, obj, index=1, close=True):
"""
Write the tag attributes common to all table objects.
"""
if not obj:
return
sp = " " * index
change_text = ' change="%d"' % obj.get_change_time()
handle_text = ' handle="_%s"' % obj.get_handle()
obj_text = '%s<%s' % (sp, tagname)
self.g.write(obj_text + handle_text + change_text)
if close:
self.g.write('>\n')

View File

@ -46,7 +46,8 @@ import Utils
import DateHandler
from gen.display.name import displayer as name_displayer
from gen.db.dbconst import (PERSON_KEY, FAMILY_KEY, SOURCE_KEY, EVENT_KEY,
MEDIA_KEY, PLACE_KEY, REPOSITORY_KEY, NOTE_KEY)
MEDIA_KEY, PLACE_KEY, REPOSITORY_KEY, NOTE_KEY,
TAG_KEY)
from gen.updatecallback import UpdateCallback
import const
import libgrampsxml
@ -198,7 +199,7 @@ class ImportInfo(object):
Class object that can hold information about the import
"""
keyorder = [PERSON_KEY, FAMILY_KEY, SOURCE_KEY, EVENT_KEY, MEDIA_KEY,
PLACE_KEY, REPOSITORY_KEY, NOTE_KEY]
PLACE_KEY, REPOSITORY_KEY, NOTE_KEY, TAG_KEY]
key2data = {
PERSON_KEY : 0,
FAMILY_KEY : 1,
@ -207,7 +208,8 @@ class ImportInfo(object):
MEDIA_KEY: 4,
PLACE_KEY: 5,
REPOSITORY_KEY: 6,
NOTE_KEY: 7
NOTE_KEY: 7,
TAG_KEY: 8
}
def __init__(self):
@ -216,8 +218,8 @@ class ImportInfo(object):
This creates the datastructures to hold info
"""
self.data_mergeoverwrite = [{},{},{},{},{},{},{},{}]
self.data_newobject = [0,0,0,0,0,0,0,0]
self.data_mergeoverwrite = [{}] * 9
self.data_newobject = [0] * 9
self.data_relpath = False
@ -257,6 +259,8 @@ class ImportInfo(object):
return _(" Repository %(id)s\n") % {'id': obj.gramps_id}
elif key == NOTE_KEY:
return _(" Note %(id)s\n") % {'id': obj.gramps_id}
elif key == TAG_KEY:
return _(" Tag %(name)s\n") % {'name': obj.get_name()}
def info_text(self):
"""
@ -271,6 +275,7 @@ class ImportInfo(object):
PLACE_KEY : _(' Places: %d\n'),
REPOSITORY_KEY : _(' Repositories: %d\n'),
NOTE_KEY : _(' Notes: %d\n'),
TAG_KEY : _(' Tags: %d\n'),
}
txt = _("Number of new objects imported:\n")
for key in self.keyorder:
@ -373,6 +378,7 @@ class GrampsParser(UpdateCallback):
self.in_note = 0
self.in_stext = 0
self.in_scomments = 0
self.note = None
self.note_text = None
self.note_tags = []
self.in_witness = False
@ -529,8 +535,11 @@ class GrampsParser(UpdateCallback):
"stext": (None, self.stop_stext),
"stitle": (None, self.stop_stitle),
"street": (None, self.stop_street),
"style": (self.start_style, None),
"suffix": (None, self.stop_suffix),
"tag": (self.start_tag, None),
"tagref": (self.start_tagref, None),
"tags": (None, None),
"text": (None, self.stop_text),
"title": (None, self.stop_title),
"url": (self.start_url, None),
@ -1321,7 +1330,10 @@ class GrampsParser(UpdateCallback):
self.name.prefix = attrs.get('prefix', '')
self.name.group_as = attrs.get('group', '')
def start_tag(self, attrs):
def start_style(self, attrs):
"""
Styled text tag in notes (v1.4.0 onwards).
"""
tagtype = gen.lib.StyledTextTagType()
tagtype.set_from_xml_str(attrs['name'])
@ -1334,6 +1346,42 @@ class GrampsParser(UpdateCallback):
return
self.note_tags.append(gen.lib.StyledTextTag(tagtype, tagvalue))
def start_tag(self, attrs):
"""
Tag definition.
"""
if self.note is not None:
# Styled text tag in notes (prior to v1.4.0)
self.start_style(attrs)
return
# Tag defintion
self.tag, new = self.db.find_tag_from_handle(
attrs['handle'].replace('_', ''), self.trans)
if new:
#keep change time from xml file
self.tag.change = int(attrs.get('change', self.change))
self.info.add('new-object', TAG_KEY, self.tag)
else:
self.tag.change = self.change
self.info.add('merge-overwrite', TAG_KEY, self.tag)
self.tag.set_name(attrs['name'])
self.tag.set_color(attrs['color'])
self.tag.set_priority(int(attrs['priority']))
self.db.commit_tag(self.tag, self.trans, self.tag.get_change_time())
def start_tagref(self, attrs):
"""
Tag reference in a primary object.
"""
handle = attrs['hlink'].replace('_', '')
self.db.check_tag_from_handle(handle, self.trans)
if self.person:
self.person.add_tag(handle)
def start_range(self, attrs):
self.note_tags[-1].ranges.append((int(attrs['start']),

View File

@ -35,5 +35,5 @@
# Public Constants
#
#------------------------------------------------------------------------
GRAMPS_XML_VERSION = "1.3.0"
GRAMPS_XML_VERSION = "1.4.0"

View File

@ -29,8 +29,8 @@ Mixin for DbDir to enable find_from_handle and check_from_handle methods.
# Gramps Modules
#
#------------------------------------------------------------------------------
from gen.lib import (GenderStats, Person, Family, Event, Place, Source,
MediaObject, Repository, Note)
from gen.lib import (Person, Family, Event, Place, Source,
MediaObject, Repository, Note, Tag)
#------------------------------------------------------------------------------
#
@ -50,10 +50,11 @@ class DbMixin(object):
where "database" is the object name of your instance of the gramps
database.
"""
def find_from_handle(self, handle, transaction, class_type, dmap,
def __find_primary_from_handle(self, handle, transaction, class_type, dmap,
add_func):
"""
Find a object of class_type in the database from the passed handle.
Find a primary object of class_type in the database from the passed
handle.
If no object exists, a new object is added to the database.
@ -74,14 +75,57 @@ class DbMixin(object):
add_func(obj, transaction)
return obj, new
def __check_from_handle(self, handle, transaction, class_type, dmap,
def __find_table_from_handle(self, handle, transaction, class_type, dmap,
add_func):
"""
Find a table object of class_type in the database from the passed
handle.
If no object exists, a new object is added to the database.
@return: Returns a tuple, first the object, second a bool which is True
if the object is new
@rtype: tuple
"""
obj = class_type()
handle = str(handle)
if handle in dmap:
obj.unserialize(dmap.get(handle))
return obj, False
else:
obj.set_handle(handle)
add_func(obj, transaction)
return obj, True
def __check_primary_from_handle(self, handle, transaction, class_type, dmap,
add_func, set_gid=True):
"""
Check whether a primary object of class_type with the passed handle
exists in the database.
If no such object exists, a new object is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
handle = str(handle)
if handle not in dmap:
obj = class_type()
obj.set_handle(handle)
add_func(obj, transaction, set_gid=set_gid)
def __check_table_from_handle(self, handle, transaction, class_type, dmap,
add_func):
"""
Check whether a table object of class_type with the passed handle exists
in the database.
If no such object exists, a new object is added to the database.
"""
handle = str(handle)
if handle not in dmap:
obj = class_type()
obj.set_handle(handle)
add_func(obj, transaction)
def find_person_from_handle(self, handle, transaction):
"""
Find a Person in the database from the passed handle.
@ -92,7 +136,7 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, Person,
return self.__find_primary_from_handle(handle, transaction, Person,
self.person_map, self.add_person)
def find_source_from_handle(self, handle, transaction):
@ -105,7 +149,7 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, Source,
return self.__find_primary_from_handle(handle, transaction, Source,
self.source_map, self.add_source)
def find_event_from_handle(self, handle, transaction):
@ -118,7 +162,7 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, Event,
return self.__find_primary_from_handle(handle, transaction, Event,
self.event_map, self.add_event)
def find_object_from_handle(self, handle, transaction):
@ -131,7 +175,7 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, MediaObject,
return self.__find_primary_from_handle(handle, transaction, MediaObject,
self.media_map, self.add_object)
def find_place_from_handle(self, handle, transaction):
@ -144,7 +188,7 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, Place,
return self.__find_primary_from_handle(handle, transaction, Place,
self.place_map, self.add_place)
def find_family_from_handle(self, handle, transaction):
@ -157,7 +201,7 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, Family,
return self.__find_primary_from_handle(handle, transaction, Family,
self.family_map, self.add_family)
def find_repository_from_handle(self, handle, transaction):
@ -170,7 +214,7 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, Repository,
return self.__find_primary_from_handle(handle, transaction, Repository,
self.repository_map, self.add_repository)
def find_note_from_handle(self, handle, transaction):
@ -183,9 +227,22 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, Note,
return self.__find_primary_from_handle(handle, transaction, Note,
self.note_map, self.add_note)
def find_tag_from_handle(self, handle, transaction):
"""
Find a Tag in the database from the passed handle.
If no such Tag exists, a new Tag is added to the database.
@return: Returns a tuple, first the object, second a bool which is True
if the object is new
@rtype: tuple
"""
return self.__find_table_from_handle(handle, transaction, Tag,
self.tag_map, self.add_tag)
def check_person_from_handle(self, handle, transaction, set_gid=True):
"""
Check whether a Person with the passed handle exists in the database.
@ -193,7 +250,7 @@ class DbMixin(object):
If no such Person exists, a new Person is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, Person,
self.__check_primary_from_handle(handle, transaction, Person,
self.person_map, self.add_person,
set_gid = set_gid)
@ -204,7 +261,7 @@ class DbMixin(object):
If no such Source exists, a new Source is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, Source,
self.__check_primary_from_handle(handle, transaction, Source,
self.source_map, self.add_source,
set_gid=set_gid)
@ -215,7 +272,7 @@ class DbMixin(object):
If no such Event exists, a new Event is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, Event,
self.__check_primary_from_handle(handle, transaction, Event,
self.event_map, self.add_event,
set_gid=set_gid)
@ -228,7 +285,7 @@ class DbMixin(object):
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, MediaObject,
self.__check_primary_from_handle(handle, transaction, MediaObject,
self.media_map, self.add_object,
set_gid=set_gid)
@ -239,7 +296,7 @@ class DbMixin(object):
If no such Place exists, a new Place is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, Place,
self.__check_primary_from_handle(handle, transaction, Place,
self.place_map, self.add_place,
set_gid=set_gid)
@ -250,7 +307,7 @@ class DbMixin(object):
If no such Family exists, a new Family is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, Family,
self.__check_primary_from_handle(handle, transaction, Family,
self.family_map, self.add_family,
set_gid=set_gid)
@ -262,7 +319,7 @@ class DbMixin(object):
If no such Repository exists, a new Repository is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, Repository,
self.__check_primary_from_handle(handle, transaction, Repository,
self.repository_map, self.add_repository,
set_gid=set_gid)
@ -273,6 +330,15 @@ class DbMixin(object):
If no such Note exists, a new Note is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, Note,
self.__check_primary_from_handle(handle, transaction, Note,
self.note_map, self.add_note,
set_gid=set_gid)
def check_tag_from_handle(self, handle, transaction):
"""
Check whether a Tag with the passed handle exists in the database.
If no such Tag exists, a new Tag is added to the database.
"""
self.__check_table_from_handle(handle, transaction, Tag,
self.tag_map, self.add_tag)