Entity / relationship pattern

Background

One of the modeling patterns supported by PageSeeder will be familiar to anyone with knowledge of Entity Relationship Diagrams (ERDs). As a long time tool for relational database developers and analysts, the screen below may help to illustrate how a PageSeeder document type can be thought of as the equivalent of a relational table.

ps-doc-type-table.png

Similarly, what appears as a row in the view above, appears more like a record in the screenshot below. In the screen below, the value of a column in the table view looks like a field in the record view.

Finally, if the name of the director was an xref to a biographical document, this would look like a join.

 

ps-doc-type-row.png

 

Based on these fundamental concepts, this article will look at an example in more detail. Using a model of a book, a publisher and more than one author, the example below how to express common data using PageSeeder objects.

book-author-publisher.svg

PageSeeder concepts

xref

In PageSeeder the rich references between documents are called xrefs, they have many properties, the ones that are relevant to this example are:

  • link type: is a processing instruction that tells PageSeeder when exporting what it should do with the linked content whether it is simple a reference or whether the content should be included;
  • reverse link: whether we want the reference to be visible to the document being referenced.

The model could be used to generate detail to be included in the front matter of a book so in that case we'd want the links between the book and the other documents to be embed, so that when the document was processed that information could be included.

We'd also want the reverse links to be true between the book and the author to be available so from the Author document we could easily see all the books they'd authored. 

Document types

PageSeeder lets you define specific document types that can capture very specifically the object you're trying to describe.  A PageSeeder document is comprised of:

  • sections: a section within PageSeeder document is used to organise content, you can lock a section or limit the fragment types that are available;
  • fragments: the basic content unit for PageSeeder, fragments contain all of the content. They can be of different types, ranging from limiting the content to a fixed set of properties or allowing for rich content to be added. A history is kept for each fragment within a document.   

A document type is a specific combination of sections, fragment types and fragments that is sympathetic to the data that is being captured.

Book

The book document properties:

  • Title: text
  • ISBN: text, with validated format
  • Author(s): reference to one or more Author documents
  • Publisher: single reference to publisher document

Publisher

The Publisher document properties:

  • Name: Text
  • Address: Text 

Author

The Author document property:

  • Name: Text

The above PageSeeder documents can be used to capture the very basics of the described model. In a production setting there would be many other options that you'd want to add depending on how the information is to be use, some obvious options are:

  • Book ISBN: enforce uniqueness of ISBN so books aren't entered multiple times 
  • Author identifiers: attributes like date of birth or global identifiers to more accurately identify the author.

The evolution of content is part of the strength of PageSeeder, allowing you to extend easily as the variations in the content become clear. 

Cardinality considerations

PageSeeder is very flexible in how the document types are constructed, but once they are set up they can enforce the model.

The 1..N relationship between publishers and books is enforced by expressing the  relationship as a single reference from the book to the publisher. This way the publisher can be referred to by many books and a book can only refer to one publisher.

PSML representation

Below are the documents described above in their PSML form, along with some advice on additional configuration options.

Book

<document level="portable" type="book">
   <section id="metadata">
      <properties-fragment id="1">
         <property name="title" title="Title" value="My story"/>
         <property name="isbn" title="ISBN" value="0864412345"/>
         <property name="category" title="Category"
                                   value="Fiction"/>    
 
        <property name="publisher"
               datatype="xref"
                  title="Publisher">
             <xref type="none"
                   frag="default" 
                   href="../../publishers/001.psml">XYZ Books</xref>
         </property>

     </properties-fragment>
  </section>
   <section id="authors">
      <title>Authors</title>
      <xref-fragment id="2">
         <blockxref type="none"
                    frag="default"
                    href="../../authors/001.psml">
                             John Jones</blockxref>
         <blockxref type="none"
                    frag="default"
                    href="../../authors/002.psml">
                             Jane Black</blockxref>
      </xref-fragment>
  </section>
</document>

 

File naming

Where multiple files need to be created, the document-config.xml can be used to automatically spawn files with unique, sequentially numbered filenames in a designated folder.

For example, to populate a folder called "books" with files that start with the name:

/books/00/001-book.psml

this code could be added to the document config:

<creation>
  <title>Book</title>
  <folder context="/books" path="{0P1000} />
  <filename value="{NNN}-book" editable="false"/>
  <document title="Book {N} {$ui.title}" docid="B{0000N}" />
</creation>

To support multiple collections of the same entity, use a * wildcard in the @context attribute of the <folder> element. For example @context=/libraries/* would create books under

/libraries/mytown/books/00/001-book.xml

or

/libraries/yourtown/books/00/001-book.xml

Be aware of potential naming clashes when PageSeeder to generate names at the same time as creating  documents externally and then uploading them to PageSeeder. Use a prefix or some other technique to prevent confusion.

 

XRefs

 To autosuggest the correct document type in an <xref-fragment>, edit the editor-config.json similar to the following example:

"
PSMLXRefsConfig": {
  "xref": {
    "type": "None"
  },
  "autosuggest" {
    "with": {
      "psdocumenttype" : "author"
    }
  }
}

Where the target document type is in multiple collections, the autosuggest can be further restricted by adding “psancestor” under "with". For example:

"psancestor" : "libraries/*"

In this example, the * will be replaced with the context of the current document. For example:

libraries/mytown

 

Author

<document level="portable" type="author">
   <section id="metadata">
      <properties-fragment id="1">
         <property name="author"
                  title="Author"
                  value="John Jones"/>
     </properties-fragment>
  </section>
</document>

 

Publisher

<document level="portable" type="publisher"> 
   <section id="metadata"> 
      <properties-fragment id="1"> 
        <property name="publisher" title="Publisher" value="XYZ Books"/>
        <property name="address" title="Address" value="P.O. Box 123, My City"/>
     </properties-fragment>
   </section> 
</document>

 

 

in your content that includes all of the attributes and information that define that object along with references to the other documents that reflect the relationships between the .  The relationships between the content can then be captured through different  

 

This patterns is suitable for data traditionally managed as fields in a relational database. The advantages of PageSeeder for this kind of application is similar to database technology  commonly known as NoSQL .

Used with this pattern, PageSeeder can be considered as a document-oriented database . Examples of documents with fielded data could be:

  • pharmaceutical data where shared information such as drug forms (tablets, capsules, soluble powders) and dosage strengths are integrated with manufacturer specific data like brands and supplier details.
  • bibliographic data that connects book metadata with author and publisher information.

Model

For use cases such as those mentioned above, an Entity-relationship  diagram is a useful tool for modelling. When expressing the diagram, make each type of content an entity then label certain fields and each relationship with the appropriate cardinality:

In PageSeeder the ER model could be implemented as follows. Remember that externally created content only needs the xref created at one end, with the reverse XRefs being created automatically.

  • A document type for each entity.
  • A <property> for each field. To improve user productivity and quality of data, consider creating a custom editor PSMLPropertiesConfig for each data set.
  • Create a <property> of @type="XRef" in order to express relationships:
    • 1 to 1,
    • 0..1 to 0..1
  • Create a <property> of @type="XRef" at the N end of each relationship. It is possible to use an xref list fragment from the 1 end of the relationship but if N is a large number this makes editing cumbersome:
    • 1 to N,
    • 0..1 to N.
  • Create an <xref-fragment> for each relationship To reduce the number of xrefs being edited this is usually done from the end for which N or M is largest.
    • N to M,
    • 0..N to 0..M.

Note the following configuration options.

File naming

Where multiple files need to be created, the document-config.xml can be used to automatically spawn files with unique, sequentially numbered filenames in a designated folder.

For example, to populate a folder called "books" with files that start with the name:

/books/00/001-book.psml

this code could be added to the document config:

<creation>
  <title>Book</title>
  <folder context="/books" path="{0P1000} />
  <filename value="{NNN}-book" editable="false"/>
  <document title="Book {N} {$ui.title}" docid="B{0000N}" />
</creation>

To support multiple collections of the same entity, use a * wildcard in the @context attribute of the <folder> element. For example @context=/libraries/* would create books under

/libraries/mytown/books/00/001-book.xml

or

/libraries/yourtown/books/00/001-book.xml

Be aware of potential naming clashes when PageSeeder to generate names at the same time as creating  documents externally and then uploading them to PageSeeder. Use a prefix or some other technique to prevent confusion.

XRefs

 To autosuggest the correct document type in an <xref-fragment>, edit the editor-config.json similar to the following example:

"
PSMLXRefsConfig": {
  "xref": {
    "type": "None"
  },
  "autosuggest" {
    "with": {
      "psdocumenttype" : "author"
    }
  }
}

Where the target document type is in multiple collections, the autosuggest can be further restricted by adding “psancestor” under "with". For example:

"psancestor" : "libraries/*"

In this example, the * will be replaced with the context of the current document. For example:

libraries/mytown

Example

 

The Entity-relationship model above could be implemented using three document types:

  • book,
  • author,
  • publisher.

Following the recommendations above:

  • the publisher relationship is expressed as 'N to 1' through a <property> element with an attribute of  @datatype and value of "xref" plus an attribute of @name and a value of "publisher" in the book instance (the N end).
  • the author relationships of 'N to M' is expressed through an <xref-fragment> in the book instance (the N end).

Below is markup representing these relationships and the other fields for the book, author and publisher.

<document level="portable" type="book">
   <section id="metadata">
      <properties-fragment id="1">
         <property name="title" title="Title" value="My story"/>
         <property name="isbn" title="ISBN" value="0864412345"/>
         <property name="category" title="Category"
                                   value="Fiction"/>    
 
        <property name="publisher"
               datatype="xref"
                  title="Publisher">
             <xref type="none"
                   frag="default" 
                   href="../../publishers/001.psml">XYZ Books</xref>
         </property>

     </properties-fragment>
  </section>
   <section id="authors">
      <title>Authors</title>
      <xref-fragment id="2">
         <blockxref type="none"
                    frag="default"
                    href="../../authors/001.psml">
                             John Jones</blockxref>
         <blockxref type="none"
                    frag="default"
                    href="../../authors/002.psml">
                             Jane Black</blockxref>
      </xref-fragment>
  </section>
</document>
<document level="portable" type="author">
   <section id="metadata">
      <properties-fragment id="1">
         <property name="author"
                  title="Author"
                  value="John Jones"/>
     </properties-fragment>
  </section>
</document>
<document level="portable" type="publisher">
   <section id="metadata">
      <properties-fragment id="1">
         <property name="publisher"
                  title="Publisher"
                  value="XYZ Books"/>
         <property name="address"
                  title="Address"
                  value="P.O. Box 123, My City"/>
     </properties-fragment>
  </section>
</document>

Created on , last edited on