dom = new DomDocument("1.0", "UTF-8");
$this->dom->formatOutput = true;
$eRoot = $this->dom->createElementNS("http://gramps-project.org/xml/1.1.0/", "database");
$eRoot = $this->dom->appendChild($eRoot);
$eHeader = $this->dom->createElement("header");
$eHeader = $eRoot->appendChild($eHeader);
$eCreated = $this->dom->createElement("created");
$eCreated = $eHeader->appendChild($eCreated);
$eCreated->setAttribute("date", date("Y-m-d"));
$eCreated->setAttribute("version", "1.1.2.6");
$eResearcher = $this->dom->createElement("researcher");
$eResname = $this->dom->createElement("resname");
$etResname = $this->dom->createTextNode(getUserFullName($user));
$etResname = $eResname->appendChild($etResname);
$eResname = $eResearcher->appendChild($eResname);
$eResemail = $this->dom->createElement("resemail");
$etResemail = $this->dom->createTextNode(getUserEmail($user));
$etResemail = $eResemail->appendChild($etResemail);
$eResemail = $eResearcher->appendChild($eResemail);
$eResearcher = $eHeader->appendChild($eResearcher);
$this->eEvents = $this->dom->createElement("events");
$this->eEvents = $eRoot->appendChild($this->eEvents);
$this->ePeople = $this->dom->createElement("people");
$this->ePeople = $eRoot->appendChild($this->ePeople);
$this->eFams = $this->dom->createElement("families");
$this->eFams = $eRoot->appendChild($this->eFams);
$this->eSources = $this->dom->createElement("sources");
$this->eSources = $eRoot->appendChild($this->eSources);
$this->ePlaces = $this->dom->createElement("places");
$this->ePlaces = $eRoot->appendChild($this->ePlaces);
$this->eObject = $this->dom->createElement("objects");
$this->eObject = $eRoot->appendChild($this->eObject);
}
/**
* Creates the date elements used throughout the GRAMPS XML file.
* The function will parse the date record and determine the type of date
* (regular, range).
*
* @param DOMObject $eParent - The parent element the date should be attached to
* @param string $dateRec - the entire GEDCOM date record to be parsed
* @param int $level - the level the date record was found on in the GEDCOM
* @param int $done - whether the method is called from the GrampsExport($done=1) or a sub-class
*/
function create_date($eParent, $dateRec, $level) {
if (empty($dateRec)) return;
$date = new GedcomDate(get_gedcom_value("DATE", $level, $dateRec, '', false));
//checks to see if there's is a 2nd date value and creates the daterange element
if (!empty($date->qual2)) {
$eDateRange = $this->dom->createElement("daterange");
$eDateRange = $eParent->appendChild($eDateRange);
//sets the start date
$eDateRange->setAttribute("start", $this->create_date_value($date->MinDate()));
//sets the stop date
$eDateRange->setAttribute("stop", $this->create_date_value($date->MaxDate()));
} else {
//if there's no dateRange, this creates the normal dateval Element
$eDateVal = $this->dom->createElement("dateval");
$eDateVal = $eParent->appendChild($eDateVal);
//checks for the Type attribute values
switch ($date->qual1) {
case 'bef':
$eDateVal->setAttribute("type", "before");
break;
case 'aft':
$eDateVal->setAttribute("type", "after");
break;
case 'abt':
$eDateVal->setAttribute("type", "about");
break;
}
//sets the date value
$eDateVal->setAttribute("val", $this->create_date_value($date->MinDate()));
}
}
/**
* Returns all the path to all media files that were used in the family, people, source in the created GRAMPS XML
*/
function get_all_media() {
return $this->mediaFiles;
}
/**
* Convert a date to the GRAMPS date format
* @param CalendarDate $date - a date to convert
*/
function create_date_value($date) {
// Since no calendar is specified, should we always convert to gregorian?
$date=$date->convert_to_cal('gregorian');
return
($date->y==0 ? '????' : $date->Format('%Y')) .'-'.
($date->m==0 ? '??' : $date->Format('%m')) .'-'.
($date->d==0 ? '??' : $date->Format('%d'));
}
/**
* Creates a reference(handle) for xml element to element in the events element of the root element
* If such an element does not exists it is created using create_event method.
* @param DOMElement $eParent - the parent you want to apend the elemnt to
* @param GEDCOM record $personrec - the record use to get more information about the event(used when the event is being created)
* @param int $event - the $event record
*/
function create_event_ref($eParent, $personrec, $event)
{
if (($eventRec = get_sub_record(1, "1 " . $event, $personrec)) != null) {
$eEventRef = $this->dom->createElement("eventref");
$eEventRef = $eParent->appendChild($eEventRef);
$eventID = $this->create_event($personrec,$event,$eventRec);
$eEventRef->setAttribute("hlink", $this->query_dom("./events/event[@id = \"$eventID\"]/@handle"));
$eParent->appendChild($eEventRef);
}
}
/**
* Creates the Event Element given the record passed and the event abbreviation which is then
* appended to the parent element passed into the method. When the Event element is created
* all it's child elements are created and appended to it accordingly. If the Place for the
* given event has not been created, this method calls create_placeobj thus creating the
* place and then links them together accordingly, otherwise the method just searches for
* the place and creates the link.
*
* @param DOMElement $personrec - the person(or top element) that contains the event
* @param string $event - the abbreviation of the event to be created; BIRT, DEAT, ADOP.....
* @param DOMElement $eventRec - the parent DOMElement to which the created Event Element is appended
* @param int $done - whether the method is called from the GrampsExport($done=1) or a sub-class
*/
function create_event($personrec, $event, $eventRec,$done=1) {
$eventID = $this->generateHandle();
$eventHandle = $eventID;
$eEvent = $this->dom->createElement("event");
$eType = $this->dom->createElement("type");
$eTypeText = $this->dom->createTextNode($event);
$eTypeText = $eType->appendChild($eTypeText);
$eEvent->appendChild($eType);
$eEvent->setAttribute("id", $eventID);
$eEvent->setAttribute("handle", $eventHandle);
$eEvent->setAttribute("change", time());
if (($dateRec = get_sub_record(1, "2 DATE", $eventRec)) != null) {
$this->create_date($eEvent, $dateRec, 2);
}
if (($place = get_gedcom_value($event . ":PLAC", 1, $personrec)) != null) {
$hlink = $this->query_dom("./places/placeobj[@title=\"".preg_replace("~\"~", '"', $place)."\"]/@handle");
if ($hlink == null) {
$hlink = $this->generateHandle();
$this->create_placeobj($place, $hlink);
$this->create_place($eEvent, $hlink);
} else {
$this->create_place($eEvent, $hlink);
}
}
if (($cause = get_gedcom_value($event . ":CAUS", 1, $personrec)) != null) {
$eCause = $this->dom->createElement("cause");
$etCause = $this->dom->createTextNode($cause);
$etCause = $eCause->appendChild($etCause);
$eCause = $eEvent->appendChild($eCause);
}
if (($description = get_gedcom_value($event . ":TYPE", 1, $personrec)) != null) {
$eDescription = $this->dom->createElement("description");
$etDescription = $this->dom->createTextNode($description);
$etDescription = $eDescription->appendChild($etDescription);
$eDescription = $eEvent->appendChild($eDescription);
}
if (($note = get_sub_record(1, "2 NOTE", $eventRec)) != null) {
$this->create_note($eEvent, $note, 2);
}
$num = 1;
while (($sourcerefRec = get_sub_record(2, "2 SOUR", $personrec, $num)) != null) {
$this->create_sourceref($eEvent, $sourcerefRec, 2);
$num++;
}
$num = 1;
while (($nameSource = get_sub_record(1, "1 OBJE", $personrec, $num)) != null) {
$this->create_mediaref($eEvent, $nameSource, 1,$done);
$num++;
}
$eEvent = $this->eEvents->appendChild($eEvent);
return $eventID;
}
/**
* This function creates a family relation for a person and appends the relation
* to the person element.
*
* It searches through the DOMDocument first to see if the person is created,
* if they are not, the person is created and then the DOMDocument is queried
* and the persons HLINK is retrieved.
*
* @param DOMElement $eParent - the parent XML element the date element should be appended to
* @param GEDCOM record $personRec - the full INDI GEDCOM record of the person that the relation is being created
* @param int $tag - the name of the GEDCOM tag (FAMC, FAMS). This is used to allow the same function to work with childin and parent_in_family relations
*/
function create_fam_relation($eParent, $personRec, $tag)
{
//throw new exception("create fam rel - this function is not implemented");
}
/**
* Creates the Family element and all of it's child elements, and appends it to the
* Families element. This function will search through the DOMDocument looking
* for people in the family. If they are not created yet and they are in the clippings
* cart, they will be created and ther hlink added to the family element.
*
* @param string $frec - the full FAM GEDCOM record of the family to be created
* @param string $fid = the ID (F1, F2, F3) of the family that is being created
*/
function create_family($frec, $fid)
{
//throw new exception("create_family - this function is not implemented");
}
/**
* Creates the lds_ord element and appends the correct information depending
* on the type of lds_ord (Endowment, Sealing, Baptism). If there is a sealing,
* the function will search if the family is in the clippings cart and if the
* family is created or not. If the family is not created yet, it will be created
* and added to the DOMDocument
*
* @param $indirec - The full INDI GEDCOM record of the person the lds_ord is being created
* @param $eventName - the name of the LDS event (Baptism, Sealing, Endowment, etc...)
* @param $eventABV - the event abbreviation in the GEDCOM (ie. SLGC, BAPL, ENDL)
* @param $eParent - The parent element the lds event is attached to
*/
function create_lds_event($indirec, $eventName, $eventABV, $eParent)
{
//throw new exception("create_lds_event - this function is not implemented");
}
/**
* Creates the Note element and appends it to the parent element
*
* @param DOMElement $eParent - the parent DOMElement to which the created Note Element is appended
* @param string $noteRec - the entire Family, Individual, etc. record in which the event may be found
* @param int $level - The GEDCOM line level where the NOTE tag may be found
*/
function create_note($eParent, $noteRec, $level) {
$note = get_gedcom_value("NOTE", $level, $noteRec);
$note .= get_cont($level+1, $noteRec, false);
// $num = 1;
// while (($cont = get_gedcom_value("NOTE:CONT", $level, $noteRec, $num)) != null) {
// $note .= $cont;
// $num++;
// }
$eNote = $this->dom->createElement("note");
$etNote = $this->dom->createTextNode(htmlentities($note,ENT_COMPAT,'UTF-8'));
$etNote = $eNote->appendChild($etNote);
$eNote = $eParent->appendChild($eNote);
}
/**
* Creates the Person element and all of it's child elements, and appends it to the
* People element. Given the link for certain LDS events to a family, if the Family
* has not been previously created, create_family is called to create the family.
* The family relations in the LDS events and in the person element are only created
* if the family they have a relation with are also included in the clippings cart
*
* @param string $personRec - the full INDI GEDCOM record of the person to be created
* @param string $personID - the ID (I1, I2, I3) of the person the is being created
*/
function create_person($personRec = "", $personID = "")
{
//throw new exception("create_person - this function is not implemented");
}
/**
* Creates the Place Element and appends it to the Parent element given
*
* @param DOMElement $eParent - the parent DOMElement to which the created Place Element is appended
* @param string $hlink - the value to which the 'hlink' attribute is set
*/
function create_place($eParent, $hlink) {
$ePlace = $this->dom->createElement("place");
$ePlace->setAttribute("hlink", $hlink);
$ePlace = $eParent->appendChild($ePlace);
}
/**
* Creates the PlaceObj element and appends it to the Places element
*
* @param string $place - the string containing the value for the placeobj to be created
* @param string $hlink - the value to which the 'hlink' attribute is set \
* @param int $done - whether the method is called from the GrampsExport($done=1) or a sub-class
*/
function create_placeobj($place, $hlink,$done=1) {
$ePlaceObj = $this->dom->createElement("placeobj");
$ePlaceObj->setAttribute("handle", $hlink);
$ePlaceObj->setAttribute("id", $hlink);
$ePlaceObj->setAttribute("change", time());
$ePTitle = $this->dom->createElement("ptitle");
$ePTitle = $ePlaceObj->appendChild($ePTitle);
$ePlaceObj = $this->ePlaces->appendChild($ePlaceObj);
$ePlaceText = $this->dom->createTextNode($place);
$ePTitle->appendChild($ePlaceText);
$num = 1;
while (($nameSource = get_sub_record(1, "1 OBJE", $place, $num)) != null) {
$this->create_mediaref($this->ePlaces, $nameSource, 1,$done);
$num++;
}
}
/**
* Creates a reference(handle) for xml element to element in the objects element of the root element
* If such an element does not exists it is created using create_media method.
* @param DOMElement $eParent - the parent you want to apend the elemnt to
* @param GEDCOM record $sourcerefRec - the record use to get more information about the event(used when the event is being created)
* @param int $level - the level the media could be found
*/
function create_mediaref($eParent, $sourcerefRec, $level,$done=1) {
$mediaId = get_gedcom_value("OBJE", $level, $sourcerefRec);
$eMediaRef = $this->dom->createElement("objref");
$eMediaRef = $eParent->appendChild($eMediaRef);
if (($sourceHlink = $this->query_dom("./objects/object[@id = \"$mediaId\"]/@handle")) == null)
$this->create_media($mediaId, find_media_record($mediaId), WT_GED_ID);
$eMediaRef->setAttribute("hlink", $this->query_dom("./objects/object[@id = \"$mediaId\"]/@handle"));
$eParent->appendChild($eMediaRef);
}
/**
* Creates an object element(for the media) and puts it unde the objects element of the root
* @param string $mediaID - the id of the media you want to create
* @param string $mediaRec - the GEDCOM record that contains the media
* @param int $level - the level the media is in the GEDCOM method
*/
function create_media($mediaID, $mediaRec, $level = 1) {
global $file;
$object = $this->dom->createElement("object");
/*primary object elements and attributes*/
$object->setAttribute("id", $mediaID);
$object->setAttribute("handle", $this->generateHandle());
$object->setAttribute("change", time());
/*elements and attributes of the object element*/
/*File elements*/
$file_ = get_gedcom_value("FILE", 1, $mediaRec);
$this->mediaFiles[] = $file_;
$fileNode = $this->dom->createElement("file");
/*Source*/
$src = $this->dom->createAttribute("src");
$srcData = $this->dom->createTextNode($file_);
$srcData = $src->appendChild($srcData);
$src = $fileNode->appendChild($src);
/*MIME*/
$mime_ = get_gedcom_value("FORM", 1, $mediaRec);
$mime = $this->dom->createAttribute("mime");
if (empty ($mime_)) {
$path = pathinfo($file_);
if(!isset($path["extension"]))
$mime_ = "unknown_file_extension";
else
$mime_ = $path["extension"];
}
$mimeData = $this->dom->createTextNode($mime_);
$mimeData = $mime->appendChild($mimeData);
$mime = $fileNode->appendChild($mime);
/*DESCRIPTION*/
$description_ = get_gedcom_value("TITL", 1, $mediaRec);
$description = $this->dom->createAttribute("description");
$descriptionData = $this->dom->createTextNode($description_);
$descriptionData = $description->appendChild($descriptionData);
$description = $fileNode->appendChild($description);
/*fileNode elements*/
$fileNode = $object->appendChild($fileNode);
$fileNode = $this->dom->createElement("file");
if (($note = get_sub_record(1, "1 NOTE", $mediaRec)) != null) {
$this->create_note($object, $note, 1);
}
$num = 1;
while (($nameSource = get_sub_record($level, $level . " SOUR", $mediaRec, $num)) != null) {
$this->create_sourceref($object, $nameSource, 1);
$num++;
}
$object = $this->eObject->appendChild($object);
//find_highlighted_media();//find the primary picture for the gedcom record
}
/**
* Creates the SourceRef element and appends it to the Parent Element. If the actual Source has not
* been previously created, this will retrieve the record for that, and create that also.
*
* @param DOMElement $eParent - the parent DOMElement to which the created Note Element is appended
* @param string $sourcerefRec - the record containing the reference to a Source
* @param int $level - The GEDCOM line level where the SOUR tag may be found
*/
function create_sourceref($eParent, $sourcerefRec, $level)
{
// throw new exception("create_sourceref - this function is not implemented");
}
/**
* Creates the Source and appends it to the Sources Element
*
* @param string $sourceID - the ID of the source to be created
* @param string $sourceRec - the entire GEDCOM record containing the Source
* @param int $level - the level the source is on in the GEDCOM record
* @param int $done - whether the method is called from the GrampsExport($done=1) or a sub-class
*/
function create_source($sourceID, $sourceRec, $level = 1, $done=1) {
$eSource = $this->dom->createElement("source");
$eSource->setAttribute("id", $sourceID);
$eSource->setAttribute("handle", $this->generateHandle());
$eSource->setAttribute("change", time());
if (($title = get_gedcom_value("TITL", $level, $sourceRec)) != null) {
$eSTitle = $this->dom->createElement("stitle");
$etSTitle = $this->dom->createTextNode($title);
$etSTitle = $eSTitle->appendChild($etSTitle);
$eSTitle = $eSource->appendChild($eSTitle);
}
if (($author = get_gedcom_value("AUTH", $level, $sourceRec)) != null) {
$eSAuthor = $this->dom->createElement("sauthor");
$etSAuthor = $this->dom->createTextNode($author);
$etSAuthor = $eSAuthor->appendChild($etSAuthor);
$eSAuthor = $eSource->appendChild($eSAuthor);
}
if (($pubInfo = get_gedcom_value("PUBL", $level, $sourceRec)) != null) {
$eSPubInfo = $this->dom->createElement("spubinfo");
$etSPubInfo = $this->dom->createTextNode($pubInfo);
$etSPubInfo = $eSPubInfo->appendChild($etSPubInfo);
$eSPubInfo = $eSource->appendChild($eSPubInfo);
}
if (($abbrev = get_gedcom_value("ABBR", $level, $sourceRec)) != null) {
$eSAbbrev = $this->dom->createElement("sabbrev");
$etSAbbrev = $this->dom->createTextNode($abbrev);
$etSAbbrev = $eSAbbrev->appendChild($etSAbbrev);
$eSAbbrev = $eSource->appendChild($eSAbbrev);
}
if (($note = get_sub_record($level, $level . " NOTE", $sourceRec)) != null) {
$this->create_note($eSource, $note, $level);
}
$num = 1;
while (($nameSource = get_sub_record(1, "1 OBJE", $sourceRec, $num)) != null) {
$this->create_mediaref($this->eSources, $nameSource, 1,$done);
$num++;
}
$eSource = $this->eSources->appendChild($eSource);
}
/**
* Generates a unique identifier for linking elements in the DOMDocument
* This function was created to conform to how GRAMPS formats their XML
* documents. The handle only has to be unique among the file, but this
* allows for a creation of a huge XML file with little chance of overlap
*/
function generateHandle() {
return strtoupper("_" . dechex(rand() * (time() * 877)) . dechex(time() * rand(1, 4)));
}
/**
* Reads in an xpath expression and returns the value searched for by the expression
*
* @param string $query - XPath expression to be executed on the DOMDocument
*
* @return string - The result of the XPath expression (null if no record is found)
*/
function query_dom($query) {
$xpath = new DOMXpath($this->dom);
$id = $xpath->query($query);
if ($id->length == 0)
$id = null;
if (isset ($id)) {
foreach ($id as $handle) {
$id = $handle->nodeValue;
}
}
return $id;
}
/**
* This function takes the dom document and validates it against the
* GRAMPS RNG schema. It then prints out the results of the validation
* to the screen.
*
* Validating against the DTD could be easily added
* if that is deemed useful.
*
* @param DOMDocument $domObj - this is the dom document to be validated
* @param boolean $printXML - set to true, this parameter will make validate print out the DOMDocuments XML to the screen
*
*/
function validate($domObj, $printXML = true) {
if ($printXML) {
print "
" . nl2br(htmlentities($domObj->saveXML(),ENT_COMPAT,'UTF-8'));
}
print "Loading GRAMPS file...
";
$domObj->loadXML($domObj->saveXML());
$res = $domObj->relaxNGValidate('includes/grampsxml.rng');
if ($res)
print "Validation: PASSED against the .RNG
";
else
print "Validation: FAILED against the .RNG
";
}
}
?>