mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-05-04 06:26:54 +00:00
The default value population algorithm introduced by commit2bfaa34
("config_tools: populate default values in scenario XML") only populates default values to the first occurrence of a tag when the tag is specified to allow multiple occurrences under an xs:all node. This may lead to incomplete scenario XML as some of the default values are missed. This patch fixes this issue by checking **all** nodes having the same tag under a node specified by an xs:all schema. Fixes:2bfaa34
("config_tools: populate default values in scenario XML") Tracked-On: #6292 Signed-off-by: Junjie Mao <junjie.mao@intel.com>
97 lines
3.8 KiB
Python
Executable File
97 lines
3.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Copyright (C) 2021 Intel Corporation. All rights reserved.
|
|
#
|
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
#
|
|
|
|
import argparse
|
|
import lxml.etree as etree
|
|
|
|
xpath_ns = {
|
|
"xs": "http://www.w3.org/2001/XMLSchema",
|
|
}
|
|
|
|
def get_node(element, xpath):
|
|
return next(iter(element.xpath(xpath, namespaces=xpath_ns)), None)
|
|
|
|
def populate_sequence(xsd_etree, xsd_sequence_node, xml_node):
|
|
children = list(xml_node)
|
|
for element_node in xsd_sequence_node.findall("xs:element", namespaces=xpath_ns):
|
|
element_name = element_node.get("name")
|
|
element_min_occurs = element_node.get("minOccurs")
|
|
|
|
if len(children) == 0:
|
|
if element_min_occurs != "0":
|
|
xml_child_node = etree.Element(element_name)
|
|
xml_node.append(xml_child_node)
|
|
populate(xsd_etree, element_node, xml_child_node, True)
|
|
elif children[0].tag != element_name:
|
|
if element_min_occurs != "0":
|
|
xml_child_node = etree.Element(element_name)
|
|
children[0].addprevious(xml_child_node)
|
|
populate(xsd_etree, element_node, xml_child_node, True)
|
|
else:
|
|
while len(children) > 0 and children[0].tag == element_name:
|
|
child_node = children.pop(0)
|
|
populate(xsd_etree, element_node, child_node, False)
|
|
|
|
def populate_all(xsd_etree, xsd_all_node, xml_node):
|
|
for element_node in xsd_all_node.findall("xs:element", namespaces=xpath_ns):
|
|
element_name = element_node.get("name")
|
|
if not element_name:
|
|
continue
|
|
xml_child_nodes = xml_node.findall(element_name)
|
|
if len(xml_child_nodes) == 0:
|
|
element_min_occurs = element_node.get("minOccurs")
|
|
if element_min_occurs == "0":
|
|
continue
|
|
|
|
xml_child_node = etree.Element(element_name)
|
|
xml_node.append(xml_child_node)
|
|
populate(xsd_etree, element_node, xml_child_node, True)
|
|
else:
|
|
for xml_child_node in xml_child_nodes:
|
|
populate(xsd_etree, element_node, xml_child_node, False)
|
|
|
|
def populate(xsd_etree, xsd_element_node, xml_node, is_new_node):
|
|
complex_type_node = xsd_element_node.find("xs:complexType", namespaces=xpath_ns)
|
|
if not complex_type_node:
|
|
type_name = xsd_element_node.get("type")
|
|
if type_name:
|
|
complex_type_node = get_node(xsd_etree, f"//xs:complexType[@name='{type_name}']")
|
|
|
|
if complex_type_node is not None:
|
|
sequence_node = complex_type_node.find("xs:sequence", namespaces=xpath_ns)
|
|
if sequence_node is not None:
|
|
populate_sequence(xsd_etree, sequence_node, xml_node)
|
|
|
|
all_node = complex_type_node.find("xs:all", namespaces=xpath_ns)
|
|
if all_node is not None:
|
|
populate_all(xsd_etree, all_node, xml_node)
|
|
elif is_new_node:
|
|
default_value = xsd_element_node.get("default")
|
|
xml_node.text = default_value
|
|
|
|
def main(xsd_file, xml_file, out_file):
|
|
xml_etree = etree.parse(xml_file, etree.XMLParser(remove_blank_text=True))
|
|
xsd_etree = etree.parse(xsd_file)
|
|
xsd_etree.xinclude()
|
|
|
|
xml_root = xml_etree.getroot()
|
|
xsd_root = get_node(xsd_etree, f"/xs:schema/xs:element[@name='{xml_root.tag}']")
|
|
|
|
if xsd_root is not None:
|
|
populate(xsd_etree, xsd_root, xml_root, False)
|
|
|
|
xml_etree.write(out_file, pretty_print=True)
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser(description="Populate a given scenario XML with default values of nonexistent nodes")
|
|
parser.add_argument("xsd", help="Path to the schema of scenario XMLs")
|
|
parser.add_argument("xml", help="Path to the scenario XML file from users")
|
|
parser.add_argument("out", default="out.xml", help="Path where the output is placed")
|
|
args = parser.parse_args()
|
|
|
|
main(args.xsd, args.xml, args.out)
|