---
# System prepended metadata

title: Presentation

---

---
title: Presentation
date: 9 Mar 2023
---

# :spiral_note_pad: Metadata Library Intorudction

:::success
:dart: **Goals**
1. **Extract** all the information from the `metadata*.xml` 
2. **Tranform** it, i.e. clean it
3. **Load** to the database.
:::

# :building_construction: How

```mermaid
graph LR


N --Api--> Havester((Havester))
E --Api--> Havester((Havester))
R --Api--> Havester((Havester))
C --Api--> Havester((Havester))

Havester --metadata*.xml--> Parser{XmlParser/XmlSerializer}--ETL-->Database[(Database)]

Database -.-> EF{EFCore} -.-> SearchBar
EF -.-> Database
SearchBar -.-> EF
```

# :gear: Serialization/Deserialization

- `XmlSerializer`
  - `C#`
    - [`XmlSerializer`](https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializer?view=net-7.0)
- `XmlParser`
  - `Python`
    - [`bs4`](https://www.crummy.com/software/BeautifulSoup/bs4/doc/)
    - [`lxml`](https://lxml.de/tutorial.html)
    - [...and more](https://realpython.com/python-xml-parser/)
  - `C#`
    - [`System.Xml.XElement`](https://learn.microsoft.com/en-us/dotnet/api/system.xml.linq.xelement?view=net-7.0)

# :gear: EF core

## :information_source: What is EF core

-  [Entity Framework (`EF`)](https://learn.microsoft.com/en-us/ef/core/get-started/overview/first-app?tabs=netcore-cli)
- A handy library for programmer to communicate with databases
- ~ to [`SQLAlchemcy`](https://www.sqlalchemy.org/) in `Python`

## :information_source: How to be use?

```csharp=
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    public string DbPath { get; }

    public BloggingContext()
    {
        var folder = Environment.SpecialFolder.LocalApplicationData;
        var path = Environment.GetFolderPath(folder);
        DbPath = System.IO.Path.Join(path, "blogging.db");
    }

    // The following configures EF to create a Sqlite database file in the
    // special "local" folder for your platform.
    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseSqlite($"Data Source={DbPath}");
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}
```


## :o: Pros

- No need to write SQL
- No need to explicitly write relation, it is declared by the class (entity)
  - 1-to-1 relationship, e.g. 1 post belongs to 1 blog, 
  - 1-to-$n$ relationship, e.g. 1 blog could have $n$ posts, 
- Programmer can use the query data as an object 
  - i.e `blog.Posts` will get you a list of post in the database
- You can easily change to different relational database without rewriting the code.
  - currently we are using `Sqlite` and trying to migrate to `PostgreSql` which is provided by `aws-rds`

## :x: Cons 

- Given you have some `C#` experience, **it takes time to learn.**
- It **could be slow when the class is complex**, i.e. if the classes have a lot of inheritance/polymorphism
- While it claims you do not need to write SQL, actually during the initial setup, you will probably need to write SQL anyway. Especially when you have complex/weird relationship between tables.


## :thinking_face: Code 1st or Database 1st?

::::info
:bulb: **Code 1st**: Write the classes first. Design the classes/relationships to init the database then load the data in the database by 
:::warning
:heavy_exclamation_mark:  Exactly what :older_adult: Vasili is doing in the metadata library.
:::

::::

::::info
:bulb: **Database 1st**: Get the data first, load it to the database as it is. write the classes/relationships according to the tables.



:::warning
:snake: **`Pythonically`**: 
1. Load each `xml` object i.e.`<sth>sth_value</sth>` into different dataframe (in RAM)
2. Keeping track of metadata `fileIdentifier` of each dataframe.
3. Load the dataframes to databse
:::

:::spoiler
**Example**
suppose our `example_metadata.xml` looks like this

```xml!
<MD_Metadata>
    <fileIdentifer>aaa-bbb-ccc-111-222-333</fileIdentifer>
    <title>dummy_title</title>
    <CI_Contact>
        <name>dummy_contact_name</name>
    </CI_Contact>
</MD_Metadata>
```

In python you will have two dataframes

`MD_Metadata_df`

|      uid       |      fileIdentifer      |    title    |    contact    |
|:--------------:|:-----------------------:|:-----------:|:-------------:|
| metadata_uid_1 | aaa-bbb-ccc-111-222-333 | dummy_title | contact_uid_1 |

`CI_Contact_df`
|      uid      |      fileIdentifer      |        name        |
|:-------------:|:-----------------------:|:------------------:|
| contact_uid_1 | aaa-bbb-ccc-111-222-333 | dummy_contact_name |

Note that `uid` can be assigned by either database/programmer. With this approach, we can have the database populated first and, at the minimum, you will know which one belong to which one.
:::



::::

