修改为东南天坐标系

This commit is contained in:
2026-01-20 09:49:52 +08:00
parent 9538757047
commit 333fad40ac
7201 changed files with 1030888 additions and 85410 deletions

View File

@@ -0,0 +1,113 @@
from __future__ import annotations
from enum import Enum
from typing import Any, Dict, Sequence, Tuple, Union
class Orientation(Enum):
SCREEN = (1, -1) # Origin in top left, y increases in the down direction
CARTESIAN = (1, 1) # Origin in bottom left, y increases in upward direction
def convert_coordinate(old_t, old_t_max, new_t_max, t_orientation):
"""Convert a coordinate into another system along an axis using a linear transformation"""
return (
(1 - old_t / old_t_max) * (1 - t_orientation) / 2
+ old_t / old_t_max * (1 + t_orientation) / 2
) * new_t_max
class CoordinateSystem:
"""A finite coordinate plane with given width and height."""
orientation: Orientation
def __init__(self, width: Union[int, float], height: Union[int, float]):
self.width = width
self.height = height
def __eq__(self, other: object):
if not isinstance(other, CoordinateSystem):
return False
return (
str(self.__class__.__name__) == str(other.__class__.__name__)
and self.width == other.width
and self.height == other.height
and self.orientation == other.orientation
)
def convert_from_relative(
self,
x: Union[float, int],
y: Union[float, int],
) -> Tuple[Union[float, int], Union[float, int]]:
"""Convert to this coordinate system from a relative coordinate system."""
x_orientation, y_orientation = self.orientation.value
new_x = convert_coordinate(x, 1, self.width, x_orientation)
new_y = convert_coordinate(y, 1, self.height, y_orientation)
return new_x, new_y
def convert_to_relative(
self,
x: Union[float, int],
y: Union[float, int],
) -> Tuple[Union[float, int], Union[float, int]]:
"""Convert from this coordinate system to a relative coordinate system."""
x_orientation, y_orientation = self.orientation.value
new_x = convert_coordinate(x, self.width, 1, x_orientation)
new_y = convert_coordinate(y, self.height, 1, y_orientation)
return new_x, new_y
def convert_coordinates_to_new_system(
self,
new_system: CoordinateSystem,
x: Union[float, int],
y: Union[float, int],
) -> Tuple[Union[float, int], Union[float, int]]:
"""Convert from this coordinate system to another given coordinate system."""
rel_x, rel_y = self.convert_to_relative(x, y)
return new_system.convert_from_relative(rel_x, rel_y)
def convert_multiple_coordinates_to_new_system(
self,
new_system: CoordinateSystem,
coordinates: Sequence[Tuple[Union[float, int], Union[float, int]]],
) -> Tuple[Tuple[Union[float, int], Union[float, int]], ...]:
"""Convert (x, y) coordinates from current system to another coordinate system."""
new_system_coordinates = []
for x, y in coordinates:
new_system_coordinates.append(
self.convert_coordinates_to_new_system(new_system=new_system, x=x, y=y),
)
return tuple(new_system_coordinates)
class RelativeCoordinateSystem(CoordinateSystem):
"""Relative coordinate system where x and y are on a scale from 0 to 1."""
orientation = Orientation.CARTESIAN
def __init__(self):
self.width = 1
self.height = 1
class PixelSpace(CoordinateSystem):
"""Coordinate system representing a pixel space, such as an image. The origin is at the top
left."""
orientation = Orientation.SCREEN
class PointSpace(CoordinateSystem):
"""Coordinate system representing a point space, such as a pdf. The origin is at the bottom
left."""
orientation = Orientation.CARTESIAN
TYPE_TO_COORDINATE_SYSTEM_MAP: Dict[str, Any] = {
"PixelSpace": PixelSpace,
"PointSpace": PointSpace,
"CoordinateSystem": CoordinateSystem,
}

View File

@@ -0,0 +1,195 @@
"""
This module contains mapping between:
HTML Tags <-> Elements Ontology <-> Unstructured Element classes
They are used to simplify transformations between different representations
of parsed documents
"""
from typing import Dict, Type
from unstructured.documents import elements, ontology
from unstructured.documents.elements import Element
def get_all_subclasses(cls: type) -> list[type]:
"""
Recursively find all subclasses of a given class.
Parameters:
cls (type): The class for which to find all subclasses.
Returns:
list[type]: A list of all subclasses of the given class.
"""
subclasses = cls.__subclasses__()
all_subclasses = subclasses.copy()
for subclass in subclasses:
all_subclasses.extend(get_all_subclasses(subclass))
return all_subclasses
def get_ontology_to_unstructured_type_mapping() -> (
dict[Type[ontology.OntologyElement], Type[Element]]
):
"""
Get a mapping of ontology element to unstructured type.
The dictionary here was created base on ontology mapping json
Can be generated via the following code:
```
ontology_elements_list = json.loads(
Path("unstructured_element_ontology.json").read_text()
)
ontology_to_unstructured_class_mapping = {
ontology_element["name"]: ontology_element["ontologyV1Mapping"]
for ontology_element in ontology_elements_list
}
```
Returns:
dict: A dictionary where keys are ontology element classes
and values are unstructured types.
"""
ontology_to_unstructured_class_mapping: Dict[Type[ontology.OntologyElement], Type[Element]] = {
ontology.Document: elements.Text,
ontology.Section: elements.Text,
ontology.Page: elements.Text,
ontology.Column: elements.Text,
ontology.Paragraph: elements.NarrativeText,
ontology.Header: elements.Header,
ontology.Footer: elements.Footer,
ontology.Sidebar: elements.Text,
ontology.PageBreak: elements.PageBreak,
ontology.Title: elements.Title,
ontology.Subtitle: elements.Title,
ontology.Heading: elements.Title,
ontology.NarrativeText: elements.NarrativeText,
ontology.Quote: elements.NarrativeText,
ontology.Footnote: elements.Text,
ontology.Caption: elements.FigureCaption,
ontology.PageNumber: elements.PageNumber,
ontology.UncategorizedText: elements.Text,
ontology.OrderedList: elements.Text,
ontology.UnorderedList: elements.Text,
ontology.DefinitionList: elements.Text,
ontology.ListItem: elements.ListItem,
ontology.Table: elements.Table,
ontology.TableRow: elements.Table,
ontology.TableCell: elements.Table,
ontology.TableCellHeader: elements.Table,
ontology.TableBody: elements.Table,
ontology.TableHeader: elements.Table,
ontology.Image: elements.Image,
ontology.Figure: elements.Image,
ontology.Video: elements.Text,
ontology.Audio: elements.Text,
ontology.Barcode: elements.Image,
ontology.QRCode: elements.Image,
ontology.Logo: elements.Image,
ontology.CodeBlock: elements.CodeSnippet,
ontology.InlineCode: elements.CodeSnippet,
ontology.Formula: elements.Formula,
ontology.Equation: elements.Formula,
ontology.FootnoteReference: elements.Text,
ontology.Citation: elements.Text,
ontology.Bibliography: elements.Text,
ontology.Glossary: elements.Text,
ontology.Author: elements.Text,
ontology.MetaDate: elements.Text,
ontology.Keywords: elements.Text,
ontology.Abstract: elements.NarrativeText,
ontology.Hyperlink: elements.Text,
ontology.TableOfContents: elements.Table,
ontology.Index: elements.Text,
ontology.Form: elements.Text,
ontology.FormField: elements.Text,
ontology.FormFieldValue: elements.Text,
ontology.Checkbox: elements.Text,
ontology.RadioButton: elements.Text,
ontology.Button: elements.Text,
ontology.Comment: elements.Text,
ontology.Highlight: elements.Text,
ontology.RevisionInsertion: elements.Text,
ontology.RevisionDeletion: elements.Text,
ontology.Address: elements.Address,
ontology.EmailAddress: elements.EmailAddress,
ontology.PhoneNumber: elements.Text,
ontology.CalendarDate: elements.Text,
ontology.Time: elements.Text,
ontology.Currency: elements.Text,
ontology.Measurement: elements.Text,
ontology.Letterhead: elements.Header,
ontology.Signature: elements.Text,
ontology.Watermark: elements.Text,
ontology.Stamp: elements.Text,
}
return ontology_to_unstructured_class_mapping
ALL_ONTOLOGY_ELEMENT_TYPES = get_all_subclasses(ontology.OntologyElement)
HTML_TAG_AND_CSS_NAME_TO_ELEMENT_TYPE_MAP: Dict[tuple[str, str], Type[ontology.OntologyElement]] = {
(tag, element_type().css_class_name): element_type
for element_type in ALL_ONTOLOGY_ELEMENT_TYPES
for tag in element_type().allowed_tags
}
CSS_CLASS_TO_ELEMENT_TYPE_MAP: Dict[str, Type[ontology.OntologyElement]] = {
element_type().css_class_name: element_type for element_type in ALL_ONTOLOGY_ELEMENT_TYPES
}
HTML_TAG_TO_DEFAULT_ELEMENT_TYPE_MAP: Dict[str, Type[ontology.OntologyElement]] = {
"a": ontology.Hyperlink,
"address": ontology.Address,
"aside": ontology.Sidebar,
"audio": ontology.Audio,
"blockquote": ontology.Quote,
"body": ontology.Document,
"button": ontology.Button,
"cite": ontology.Citation,
"code": ontology.CodeBlock,
"del": ontology.RevisionDeletion,
"div": ontology.UncategorizedText,
"dl": ontology.DefinitionList,
"figcaption": ontology.Caption,
"figure": ontology.Figure,
"footer": ontology.Footer,
"form": ontology.Form,
"h1": ontology.Title,
"h2": ontology.Subtitle,
"h3": ontology.Heading,
"h4": ontology.Heading,
"h5": ontology.Heading,
"h6": ontology.Heading,
"header": ontology.Header,
"hr": ontology.PageBreak,
"img": ontology.Image,
"input": ontology.Checkbox,
"ins": ontology.RevisionInsertion,
"label": ontology.FormField,
"li": ontology.ListItem,
"mark": ontology.Highlight,
"math": ontology.Equation,
"meta": ontology.Keywords,
"nav": ontology.Index,
"ol": ontology.OrderedList,
"p": ontology.Paragraph,
"pre": ontology.CodeBlock,
"section": ontology.Section,
"span": ontology.UncategorizedText,
"sub": ontology.FootnoteReference,
"svg": ontology.Signature,
"table": ontology.Table,
"tbody": ontology.TableBody,
"td": ontology.TableCell,
"th": ontology.TableCellHeader,
"thead": ontology.TableHeader,
"time": ontology.Time,
"tr": ontology.TableRow,
"ul": ontology.UnorderedList,
"video": ontology.Video,
}
ONTOLOGY_CLASS_TO_UNSTRUCTURED_ELEMENT_TYPE = get_ontology_to_unstructured_type_mapping()

View File

@@ -0,0 +1,622 @@
"""
This file contains all classes allowed in the ontology V2.
This Type is used as intermediate representation between HTML
and Unstructured Elements.
All the processing could be done without the intermediate representation,
but it simplifies the process.
It needs to be decide whether we keep it or not.
The classes are represented as pydantic models to mimic Unstructured Elements V1 solutions.
However it results in lots of code that could be strongly simplified.
TODO (Pluto): OntologyElement is the only needed class. It could contains data about
allowed html tags, css classes and descriptions as metadata.
"""
from __future__ import annotations
import uuid
from copy import copy
from enum import Enum
from typing import Any, List, Optional
from bs4 import BeautifulSoup
from pydantic import BaseModel, Field
class ElementTypeEnum(str, Enum):
layout = "Layout"
text = "Text"
list = "List"
table = "Table"
media = "Media"
code = "Code"
mathematical = "Mathematical"
reference = "Reference"
metadata = "Metadata"
navigation = "Navigation"
form = "Form"
annotation = "Annotation"
specialized_text = "Specialized Text"
document_specific = "Document-Specific"
class OntologyElement(BaseModel):
text: Optional[str] = Field("", description="Text content of the element")
css_class_name: Optional[str] = Field(
default_factory=lambda: "", description="CSS class associated with the element"
)
html_tag_name: Optional[str] = Field(
default_factory=lambda: "", description="HTML Tag name associated with the element"
)
elementType: ElementTypeEnum = Field(description="Type of the element")
children: list["OntologyElement"] = Field(
default_factory=list, description="List of child elements"
)
description: str = Field(description="Description of the element")
allowed_tags: list[str] = Field(description="HTML tags associated with the element")
additional_attributes: dict[str, Any] = Field(
default_factory=dict, description="Optional HTML attributes or CSS properties"
)
def __init__(self, **kwargs: dict[str, Any]):
super().__init__(**kwargs)
if self.css_class_name == "": # if None, then do not set
self.css_class_name = self.__class__.__name__
if self.html_tag_name == "":
self.html_tag_name = self.allowed_tags[0]
if "id" not in self.additional_attributes:
self.additional_attributes["id"] = self.generate_unique_id()
@staticmethod
def generate_unique_id() -> str:
return str(uuid.uuid4()).replace("-", "")
def to_html(self, add_children: bool = True) -> str:
additional_attrs = copy(self.additional_attributes)
additional_attrs.pop("class", None)
additional_attrs.pop("id", None)
attr_str = self._construct_attribute_string(additional_attrs)
class_attr = f'class="{self.css_class_name}"' if self.css_class_name else ""
combined_attr_str = f"{class_attr} {attr_str}".strip()
children_html = self._generate_children_html(add_children)
result_html = self._generate_final_html(combined_attr_str, children_html)
return result_html
def to_text(self, add_children: bool = True, add_img_alt_text: bool = True) -> str:
"""
Returns the text representation of the element.
Args:
add_children: If True, the text of the children will be included.
Otherwise, element is represented as single self-closing tag.
add_img_alt_text: If True, the alt text of the image will be included.
"""
if self.children and add_children:
children_text = " ".join(
child.to_text(add_children, add_img_alt_text).strip() for child in self.children
)
return children_text
text = BeautifulSoup(self.to_html(), "html.parser").get_text().strip()
if add_img_alt_text and self.html_tag_name == "img" and "alt" in self.additional_attributes:
text += f" {self.additional_attributes.get('alt', '')}"
return text.strip()
def _construct_attribute_string(self, attributes: dict[str, str]) -> str:
return " ".join(
f'{key}="{value}"' if value else f"{key}" for key, value in attributes.items()
)
def _generate_children_html(self, add_children: bool) -> str:
if not add_children or not self.children:
return ""
return "".join(child.to_html() for child in self.children)
def _generate_final_html(self, attr_str: str, children_html: str) -> str:
text = self.text or ""
if text or children_html:
inside_tag_text = f"{text} {children_html}".strip()
return f"<{self.html_tag_name} {attr_str}>{inside_tag_text}</{self.html_tag_name}>"
else:
return f"<{self.html_tag_name} {attr_str} />"
@property
def id(self) -> str | None:
return self.additional_attributes.get("id", None)
@property
def page_number(self) -> int | None:
if "data-page-number" in self.additional_attributes:
try:
page_attr = self.additional_attributes.get("data-page-number")
if page_attr is not None:
return int(page_attr)
except ValueError:
return None
return None
def remove_ids_and_class_from_table(
soup: BeautifulSoup, class_attr_to_keep: list[str] = ["img", "input"]
) -> BeautifulSoup:
"""
Remove id and class attributes from tags inside tables,
except preserve class attributes for selected tags.
Args:
soup: BeautifulSoup object containing the HTML
class_attr_to_keep: a list of tag names whose class attr will be kept
Returns:
BeautifulSoup: Modified soup with attributes removed
"""
for tag in soup.find_all(True):
if tag.name.lower() == "table": # type: ignore
continue # We keep table tag
tag.attrs.pop("id", None) # type: ignore
if tag.name.lower() not in class_attr_to_keep: # type: ignore
tag.attrs.pop("class", None) # type: ignore
return soup
# Define specific elements
class Document(OntologyElement):
description: str = Field("Root element of the document", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.layout, frozen=True)
allowed_tags: List[str] = Field(["body"], frozen=True)
class Section(OntologyElement):
description: str = Field("A distinct part or subdivision of a document", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.layout, frozen=True)
allowed_tags: List[str] = Field(["section"], frozen=True)
class Page(OntologyElement):
description: str = Field("A single side of a paper in a document", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.layout, frozen=True)
allowed_tags: List[str] = Field(["div"], frozen=True)
class Column(OntologyElement):
description: str = Field("A vertical section of a page", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.layout, frozen=True)
allowed_tags: List[str] = Field(["div"], frozen=True)
class Paragraph(OntologyElement):
description: str = Field("A self-contained unit of discourse in writing", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.text, frozen=True)
allowed_tags: List[str] = Field(["p"], frozen=True)
class Header(OntologyElement):
description: str = Field("The top section of a page", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.text, frozen=True)
allowed_tags: List[str] = Field(["header"], frozen=True)
class Footer(OntologyElement):
description: str = Field("The bottom section of a page", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.text, frozen=True)
allowed_tags: List[str] = Field(["footer"], frozen=True)
class Sidebar(OntologyElement):
description: str = Field("A side section of a page", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.layout, frozen=True)
allowed_tags: List[str] = Field(["aside"], frozen=True)
class PageBreak(OntologyElement):
description: str = Field("A break between pages", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.layout, frozen=True)
allowed_tags: List[str] = Field(["hr"], frozen=True)
class Title(OntologyElement):
description: str = Field("Main heading of a document or section", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.text, frozen=True)
allowed_tags: List[str] = Field(["h1"], frozen=True)
class Subtitle(OntologyElement):
description: str = Field("Secondary title of a document or section", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.text, frozen=True)
allowed_tags: List[str] = Field(["h2"], frozen=True)
class Heading(OntologyElement):
description: str = Field("Section headings (levels 1-6)", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.text, frozen=True)
allowed_tags: List[str] = Field(["h1", "h2", "h3", "h4", "h5", "h6"], frozen=True)
class NarrativeText(OntologyElement):
description: str = Field("Main content text", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.text, frozen=True)
allowed_tags: List[str] = Field(["p"], frozen=True)
class Quote(OntologyElement):
description: str = Field("A repetition of someone else's statement", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.text, frozen=True)
allowed_tags: List[str] = Field(["blockquote"], frozen=True)
class Footnote(OntologyElement):
description: str = Field("A note at the bottom of a page", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.text, frozen=True)
allowed_tags: List[str] = Field(["div"], frozen=True)
class Caption(OntologyElement):
description: str = Field("Text describing a figure or image", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.text, frozen=True)
allowed_tags: List[str] = Field(["figcaption"], frozen=True)
class PageNumber(OntologyElement):
description: str = Field("The number of a page", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.text, frozen=True)
allowed_tags: List[str] = Field(["span"], frozen=True)
class UncategorizedText(OntologyElement):
description: str = Field("Miscellaneous text", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.text, frozen=True)
allowed_tags: List[str] = Field(["span"], frozen=True)
class OrderedList(OntologyElement):
description: str = Field("A list with a specific sequence", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.list, frozen=True)
allowed_tags: List[str] = Field(["ol"], frozen=True)
class UnorderedList(OntologyElement):
description: str = Field("A list without a specific sequence", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.list, frozen=True)
allowed_tags: List[str] = Field(["ul"], frozen=True)
class DefinitionList(OntologyElement):
description: str = Field("A list of terms and their definitions", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.list, frozen=True)
allowed_tags: List[str] = Field(["dl"], frozen=True)
class ListItem(OntologyElement):
description: str = Field("An item in a list", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.list, frozen=True)
allowed_tags: List[str] = Field(["li"], frozen=True)
class Table(OntologyElement):
description: str = Field("A structured set of data", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.table, frozen=True)
allowed_tags: List[str] = Field(["table"], frozen=True)
def to_html(self, add_children: bool = True) -> str:
soup = BeautifulSoup(super().to_html(add_children), "html.parser")
soup = remove_ids_and_class_from_table(soup)
return str(soup)
class TableBody(OntologyElement):
description: str = Field("A body of the table", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.table, frozen=True)
allowed_tags: List[str] = Field(["tbody"], frozen=True)
class TableHeader(OntologyElement):
description: str = Field("A header of the table", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.table, frozen=True)
allowed_tags: List[str] = Field(["thead"], frozen=True)
class TableRow(OntologyElement):
description: str = Field("A row in a table", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.table, frozen=True)
allowed_tags: List[str] = Field(["tr"], frozen=True)
class TableCell(OntologyElement):
description: str = Field("A cell in a table", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.table, frozen=True)
allowed_tags: List[str] = Field(["td"], frozen=True)
# Note(Pluto): Renamed from TableCellHeader to TableHeaderCell to be consistent with TableCell
class TableCellHeader(OntologyElement):
description: str = Field("A header cell in a table", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.table, frozen=True)
allowed_tags: List[str] = Field(["th"], frozen=True)
class Image(OntologyElement):
description: str = Field("A visual representation", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.media, frozen=True)
allowed_tags: List[str] = Field(["img"], frozen=True)
class Figure(OntologyElement):
description: str = Field("An illustration or diagram in a document", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.media, frozen=True)
allowed_tags: List[str] = Field(["figure"], frozen=True)
class Video(OntologyElement):
description: str = Field("A moving visual media element", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.media, frozen=True)
allowed_tags: List[str] = Field(["video"], frozen=True)
class Audio(OntologyElement):
description: str = Field("A sound or music element", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.media, frozen=True)
allowed_tags: List[str] = Field(["audio"], frozen=True)
class Barcode(OntologyElement):
description: str = Field("A machine-readable representation of data", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.media, frozen=True)
allowed_tags: List[str] = Field(["img"], frozen=True)
class QRCode(OntologyElement):
description: str = Field("A two-dimensional barcode", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.media, frozen=True)
allowed_tags: List[str] = Field(["img"], frozen=True)
class Logo(OntologyElement):
description: str = Field("A graphical representation of a company or brand", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.media, frozen=True)
allowed_tags: List[str] = Field(["img"], frozen=True)
class CodeBlock(OntologyElement):
description: str = Field("A block of programming code", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.code, frozen=True)
allowed_tags: List[str] = Field(["pre", "code"], frozen=True)
class InlineCode(OntologyElement):
description: str = Field("Code within a line of text", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.code, frozen=True)
allowed_tags: List[str] = Field(["code"], frozen=True)
class Formula(OntologyElement):
description: str = Field("A mathematical formula", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.mathematical, frozen=True)
allowed_tags: List[str] = Field(["math"], frozen=True)
class Equation(OntologyElement):
description: str = Field("A mathematical equation", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.mathematical, frozen=True)
allowed_tags: List[str] = Field(["math"], frozen=True)
class FootnoteReference(OntologyElement):
description: str = Field(
"A subscripted reference to a note at the bottom of a page", frozen=True
)
elementType: ElementTypeEnum = Field(ElementTypeEnum.reference, frozen=True)
allowed_tags: List[str] = Field(["sub"], frozen=True)
class Citation(OntologyElement):
description: str = Field("A reference to a source", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.reference, frozen=True)
allowed_tags: List[str] = Field(["cite"], frozen=True)
class Bibliography(OntologyElement):
description: str = Field("A list of sources", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.reference, frozen=True)
allowed_tags: List[str] = Field(["ul"], frozen=True)
class Glossary(OntologyElement):
description: str = Field("A list of terms and their definitions", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.reference, frozen=True)
allowed_tags: List[str] = Field(["dl"], frozen=True)
class Author(OntologyElement):
description: str = Field("The creator of the document", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.metadata, frozen=True)
allowed_tags: List[str] = Field(["meta"], frozen=True)
class MetaDate(OntologyElement):
description: str = Field("The date associated with the document", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.metadata, frozen=True)
allowed_tags: List[str] = Field(["meta"], frozen=True)
class Keywords(OntologyElement):
description: str = Field("Key terms associated with the document", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.metadata, frozen=True)
allowed_tags: List[str] = Field(["meta"], frozen=True)
class Abstract(OntologyElement):
description: str = Field("A summary of the document", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.metadata, frozen=True)
allowed_tags: List[str] = Field(["section"], frozen=True)
class Hyperlink(OntologyElement):
description: str = Field("A reference to data that can be directly followed", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.navigation, frozen=True)
allowed_tags: List[str] = Field(["a"], frozen=True)
class TableOfContents(OntologyElement):
description: str = Field(
"A list of the document's contents. Total table columns will be "
"equal to the degree of hierarchy (n) plus 1 for the target value. "
"Header Row: L1,L2,...Ln,Value",
frozen=True,
)
elementType: ElementTypeEnum = Field(ElementTypeEnum.table, frozen=True)
allowed_tags: List[str] = Field(["table"], frozen=True)
def to_html(self, add_children: bool = True) -> str:
soup = BeautifulSoup(super().to_html(add_children), "html.parser")
soup = remove_ids_and_class_from_table(soup)
return str(soup)
class Index(OntologyElement):
description: str = Field("An alphabetical list of terms and their page numbers", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.navigation, frozen=True)
allowed_tags: List[str] = Field(["nav"], frozen=True)
class Form(OntologyElement):
description: str = Field("A document section with interactive controls", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.form, frozen=True)
allowed_tags: List[str] = Field(["form"], frozen=True)
class FormField(OntologyElement):
description: str = Field("A property value of a form", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.form, frozen=True)
allowed_tags: List[str] = Field(["label"], frozen=True)
class FormFieldValue(OntologyElement):
description: str = Field("A field for user input", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.form, frozen=True)
allowed_tags: List[str] = Field(["input"], frozen=True)
def to_text(self, add_children: bool = True, add_img_alt_text: bool = True) -> str:
text = super().to_text(add_children, add_img_alt_text)
value = self.additional_attributes.get("value", "")
if not value:
return text
return f"{text} {value}".strip()
class Checkbox(OntologyElement):
description: str = Field("A small box that can be checked or unchecked", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.form, frozen=True)
allowed_tags: List[str] = Field(["input"], frozen=True)
class RadioButton(OntologyElement):
description: str = Field("A circular button that can be selected", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.form, frozen=True)
allowed_tags: List[str] = Field(["input"], frozen=True)
class Button(OntologyElement):
description: str = Field("An interactive button element", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.form, frozen=True)
allowed_tags: List[str] = Field(["button"], frozen=True)
class Comment(OntologyElement):
description: str = Field("A note or remark", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.annotation, frozen=True)
allowed_tags: List[str] = Field(["span"], frozen=True)
class Highlight(OntologyElement):
description: str = Field("Emphasized text or section", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.annotation, frozen=True)
allowed_tags: List[str] = Field(["mark"], frozen=True)
class RevisionInsertion(OntologyElement):
description: str = Field("A changed or edited element", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.annotation, frozen=True)
allowed_tags: List[str] = Field(["ins"], frozen=True)
class RevisionDeletion(OntologyElement):
description: str = Field("A changed or edited element", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.annotation, frozen=True)
allowed_tags: List[str] = Field(["del"], frozen=True)
class Address(OntologyElement):
description: str = Field("A physical location", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.specialized_text, frozen=True)
allowed_tags: List[str] = Field(["address"], frozen=True)
class EmailAddress(OntologyElement):
description: str = Field("An email address", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.specialized_text, frozen=True)
allowed_tags: List[str] = Field(["a"], frozen=True)
class PhoneNumber(OntologyElement):
description: str = Field("A telephone number", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.specialized_text, frozen=True)
allowed_tags: List[str] = Field(["span"], frozen=True)
class CalendarDate(OntologyElement):
description: str = Field("A calendar date", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.specialized_text, frozen=True)
allowed_tags: List[str] = Field(["time"], frozen=True)
class Time(OntologyElement):
description: str = Field("A specific time", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.specialized_text, frozen=True)
allowed_tags: List[str] = Field(["time"], frozen=True)
class Currency(OntologyElement):
description: str = Field("A monetary value", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.specialized_text, frozen=True)
allowed_tags: List[str] = Field(["span"], frozen=True)
class Measurement(OntologyElement):
description: str = Field("A quantitative value with units", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.specialized_text, frozen=True)
allowed_tags: List[str] = Field(["span"], frozen=True)
class Letterhead(OntologyElement):
description: str = Field("The heading at the top of a letter", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.document_specific, frozen=True)
allowed_tags: List[str] = Field(["header"], frozen=True)
class Signature(OntologyElement):
description: str = Field("A person's name written in a distinctive way", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.document_specific, frozen=True)
allowed_tags: List[str] = Field(["img", "svg"], frozen=True)
class Watermark(OntologyElement):
description: str = Field("A faint design made in paper during manufacture", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.document_specific, frozen=True)
allowed_tags: List[str] = Field(["div"], frozen=True)
class Stamp(OntologyElement):
description: str = Field("An official mark or seal", frozen=True)
elementType: ElementTypeEnum = Field(ElementTypeEnum.document_specific, frozen=True)
allowed_tags: List[str] = Field(["img", "svg"], frozen=True)