VTdevelops/bond-text-extraction
0
1from __future__ import annotations2 3from lxml import etree4 5from .models import BondRecord6 7FIELD_GROUPS: list[tuple[str, list[tuple[str, str]]]] = [8 (9 "GeneralInformation",10 [11 ("Status", "status"),12 ("EffectiveFrom", "effective_from"),13 ],14 ),15 (16 "Identification",17 [18 ("ISIN", "isin"),19 ("Valor", "valor"),20 ],21 ),22 (23 "ProductDetails",24 [25 ("Denomination", "denomination"),26 ("IssueSize", "issue_size"),27 ("LegalVenue", "legal_venue"),28 ("SecurityRanking", "security_ranking"),29 ("IssuePriceRate", "issue_price_rate"),30 ("JurisdictionCountry", "jurisdiction_country"),31 ("SecurityCategory", "security_category"),32 ("Collateralization", "collateralization"),33 ],34 ),35 (36 "Terms",37 [38 ("CallablePutable", "callable_putable"),39 ("Prolongable", "prolongable"),40 ("Amortizable", "amortizable"),41 ("Increasable", "increasable"),42 ],43 ),44 (45 "ProductDates",46 [47 ("IssueDate", "issue_date"),48 ("PaymentDate", "payment_date"),49 ("RedemptionDate", "redemption_date"),50 ],51 ),52 (53 "CouponPayment",54 [55 ("CouponFrequency", "coupon_frequency"),56 ("AnnualRate", "annual_rate"),57 ("IncomeBegin", "income_begin"),58 ("FirstPaymentDate", "first_payment_date"),59 ("DayCountMethod", "day_count_method"),60 ("EarningSpecification", "earning_specification"),61 ],62 ),63 (64 "Summary",65 [66 ("InterestRate", "interest_rate"),67 ("Rating", "rating"),68 ],69 ),70]71 72 73def build_bond_xml(records: list[BondRecord]) -> str:74 """Serialise *records* into the required XML document."""75 76 root = etree.Element("Bonds")77 for record in records:78 bond_el = etree.SubElement(root, "Bond")79 for section_name, field_specs in FIELD_GROUPS:80 section_el = etree.SubElement(bond_el, section_name)81 for tag, attr in field_specs:82 value = getattr(record, attr, "")83 _append_text_element(section_el, tag, value)84 85 xml_bytes = etree.tostring(86 root,87 encoding="utf-8",88 xml_declaration=True,89 pretty_print=True,90 )91 return xml_bytes.decode("utf-8")92 93 94def _append_text_element(parent: etree._Element, tag: str, text: str) -> None:95 child = etree.SubElement(parent, tag)96 child.text = text or ""97 