I'm using Python's xml.etree.ElementTree
to generate XML, and I’m encountering an issue where an XML subelement appears under a different tag than intended.
My function looks like this:
def generate_product (parentElement, products: dict):
for product_id, product_detail in products.items():
product = ET.SubElement(parentElement, "PRODUCT")
supplier_pid = ET.SubElement(product, "SUPPLIER_PID")
supplier_pid.text = product_detail["supplier_pid"]
product_details = ET.SubElement(product, "PRODUCT_DETAILS")
description_short = ET.SubElement(product_details, "DESCRIPTION_SHORT")
description_short.text = product_detail["description_short"]
ean = ET.SubElement(product_details, "EAN")
ean.text = product_detail["ean"]
manufacturer_pid = ET.SubElement(product_details, "MANUFACTURER_PID")
manufacturer_pid.text = product_detail["manufacturer_pid"]
manufacturer_name = ET.SubElement(product_details, "MANUFACTURER_NAME")
manufacturer_name.text = product_detail["manufacturer_name"]
delivery_time = ET.SubElement(product_details, "DELIVERY_TIME")
delivery_time.text = product_detail["delivery_time"]
product_features = ET.SubElement(product, "PRODUCT_FEATURES")
reference_feature_system_name = ET.SubElement(product_features, "REFERENCE_FEATURE_SYSTEM_NAME")
reference_feature_system_name.text = product_detail["reference_feature_system_name"]
reference_feature_group_id = ET.SubElement(product_features, "REFERENCE_FEATURE_GROUP_ID")
reference_feature_group_id.text = product_detail["reference_feature_group_id"]
product_order_details = ET.SubElement(product, "PRODUCT_ORDER_DETAILS")
order_unit = ET.SubElement(product_order_details, "ORDER_UNIT")
order_unit.text = product_detail["order_unit"]
price_quantity = ET.SubElement(product_order_details, "PRICE_QUANTITY")
price_quantity.text = product_detail["price_quantity"]
quantity_min = ET.SubElement(product_order_details, "QUANTITY_MIN")
quantity_min.text = product_detail["quantity_min"]
quantity_interval = ET.SubElement(product_order_details, "QUANTITY_INTERVAL")
quantity_interval.text = product_detail["quantity_interval"]
product_price_details = ET.SubElement(product, "PRODUCT_PRICE_DETAILS")
product_price_details_start_datetime = ET.SubElement(product_price_details, "DATETIME", attrib={"type":"valid_start_date"})
price_start_date = ET.SubElement(product_price_details_start_datetime, "DATE")
price_start_date.text = product_detail["valid_start_date"]
product_price_details_end_datetime = ET.SubElement(product_price_details, "DATETIME", attrib={"type":"valid_end_date"})
price_end_date = ET.SubElement(product_price_details_end_datetime, "DATE")
price_end_date.text = product_detail["valid_end_date"]
if product_detail["daily_price"] == "TRUE":
daily_price = ET.SubElement(product_price_details, "DAILY_PRICE")
daily_price.text = "true"
product_price = ET.SubElement(product_price_details, "PRODUCT_PRICE", attrib={"price_type":f"{product_detail['price_type']}"})
price_amount = ET.SubElement(product_price, "PRICE_AMOUNT")
price_amount.text = product_detail["price_amount"]
price_currency = ET.SubElement(product_price, "PRICE_CURRENCY")
price_currency.text = product_detail["price_currency"]
tax = ET.SubElement(product_price, "TAX")
tax.text = product_detail["tax"]
mime_info = ET.SubElement(product, "MIME_INFO")
mime = ET.SubElement(mime_info, "MIME")
mime_type = ET.SubElement(mime, "MIME_TYPE")
mime_type.text = product_detail["mime_type"]
mime_source = ET.SubElement(mime, "MIME_SOURCE")
mime_source.text = product_detail["mime_source"]
mime_descr = ET.SubElement(mime, "MIME_DESCR")
mime_descr.text = product_detail["mime_descr"]
mime_purpose = ET.SubElement(mime, "MIME_PURPOSE")
mime_purpose.text = product_detail["mime_purpose"]
mime_order = ET.SubElement(mime, "MIME_ORDER")
mime_order.text = product_detail["mime_order"]
And the placement problem happens at this place in the code:
product_price_details = ET.SubElement(product, "PRODUCT_PRICE_DETAILS")
product_price_details_start_datetime = ET.SubElement(product_price_details, "DATETIME", attrib={"type":"valid_start_date"})
price_start_date = ET.SubElement(product_price_details_start_datetime, "DATE")
price_start_date.text = product_detail["valid_start_date"]
product_price_details_end_datetime = ET.SubElement(product_price_details, "DATETIME", attrib={"type":"valid_end_date"})
price_end_date = ET.SubElement(product_price_details_end_datetime, "DATE")
price_end_date.text = product_detail["valid_end_date"]
if product_detail["daily_price"] == "TRUE":
daily_price = ET.SubElement(product_price_details, "DAILY_PRICE")
daily_price.text = "true"
When I run this code, the DAILY_PRICE
element ends up inside the DATETIME
element with type valid_end_date
, instead of being placed directly under PRODUCT_PRICE_DETAILS
.
<PRODUCT_PRICE_DETAILS>
<DATETIME type="valid_start_date">
<DATE>2024-08-14</DATE>
</DATETIME>
<DATETIME type="valid_end_date">
<DATE>2024-09-30</DATE>
<DAILY_PRICE>TRUE</DAILY_PRICE>
</DATETIME>
</PRODUCT_PRICE_DETAILS>
How can I ensure that DAILY_PRICE
is correctly placed directly under PRODUCT_PRICE_DETAILS
and not inside DATETIME
?
Change the order, like:
product_price_details = ET.SubElement(product, "PRODUCT_PRICE_DETAILS")
if product_detail["daily_price"] == "TRUE":
daily_price = ET.SubElement(product_price_details, "DAILY_PRICE")
daily_price.text = "true"
product_price_details_start_datetime = ET.SubElement(product_price_details, "DATETIME", attrib={"type":"valid_start_date"})
price_start_date = ET.SubElement(product_price_details_start_datetime, "DATE")
price_start_date.text = product_detail["valid_start_date"]
product_price_details_end_datetime = ET.SubElement(product_price_details, "DATETIME", attrib={"type":"valid_end_date"})
price_end_date = ET.SubElement(product_price_details_end_datetime, "DATE")
price_end_date.text = product_detail["valid_end_date"]
product_price = ET.SubElement(product_price_details, "PRODUCT_PRICE", attrib={"price_type":f"{product_detail['price_type']}"})
Output:
<PRODUCT_PRICE_DETAILS>
<DAILY_PRICE>true</DAILY_PRICE>
<DATETIME type="valid_start_date">
<DATE>2024</DATE>
</DATETIME>
<DATETIME type="valid_end_date">
<DATE>2025</DATE>
</DATETIME>
<PRODUCT_PRICE price_type="EURO" />
</PRODUCT_PRICE_DETAILS>