javaxmlxsdxml-parsingxmlschema

Apache XMLSchema core XSD/XML parser shows the root element as parent for all children instead of its immediate parent


I am trying to parse the XSD using Apache XMLSchema Core. I am able to parse the file and store the Parent and its Child Element information within the HashMap.

Each Child element is stored in the type XmlSchemaElement which also consists of the Parent information of that child element. When I try to see the information related to a child element it shows the Root element for all instead of its immediate parent.

For example: In my XSD, RestaurantMenu is the Root element and its immediate children are Food. Also, Food has childrens name, price, calories etc. When I see the parent element for name I would expect it to be Food as that's the immediate Parent but during Debug shows the RestaurantMenu as its parent which is a bit confusing.

I wanted to know how can I get the information related to the immediate parent for each element.

Following is my XSD file:

<xs:schema attributeFormDefault="unqualified"
    elementFormDefault="qualified"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="RestaurantMenu">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="food" maxOccurs="5" minOccurs="0">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element type="xs:string" name="name" />
                            <xs:element type="xs:string" name="price" />
                            <xs:element type="xs:string" name="description" />
                            <xs:element type="xs:short" name="calories" />
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

Following is the code I have which is written using the Apache XmlSchema Core XML Parser: I am trying to Debug at the point :

List<XmlSchemaElement> childElements = getElementType(new QName("food"));
System.out.println(childElements.get(0));

Above code will return all the Children element of food: name, price, calories, description, ingredients. Then I am trying to see the parent for one of the element i.e name. Following is the debug path I am taking:

childElements -> [0] -> namedDelegate -> parentSchema -> items -> [0] -> namedDelegate -> qName.

In this qName I was expecting the food as thats my immediate parent but I get the RestaurantMenu which is my Root xsd element.

Please find the complete code below:

public class TestParser {

    private static XmlSchemaCollection xmlSchemaCollection;
    private static Map<QName, List<XmlSchemaElement>> xsdElements = new HashMap<QName, List<XmlSchemaElement>>();
    private static List<XmlSchemaElement> schemaElements = new ArrayList<XmlSchemaElement>();

    public static void main(String[] args) throws URISyntaxException, FileNotFoundException, UnsupportedEncodingException {
        // Path for the file which is stored within the Resource folder
        String xsdPath = Paths.get(TestParser.class.getClassLoader().getResource("test.xsd").toURI()).toFile().getAbsolutePath();
        String filePath = Path.of(xsdPath).toString();

        InputStream is = new FileInputStream(filePath);
        xmlSchemaCollection = new XmlSchemaCollection();

        // Schema contain the complete XSD content which needs to be parsed
        XmlSchema schema = xmlSchemaCollection.read(new StreamSource(is));
        // schema.write(System.out);

        // Get the root element from XSD
        Map.Entry<QName, XmlSchemaElement> entry = schema.getElements().entrySet().iterator().next();

        // Get all the elements based on the parent element
        XmlSchemaElement childElement = xmlSchemaCollection.getElementByQName(entry.getKey());

        // Call method to get all the child elements
        getChildElementNames(childElement);

        // Get the elements type based on choice
        List<XmlSchemaElement> childElements = xsdElements.get(new QName("food"));
        System.out.println(childElements.get(0));

    }

    // Method to check for the child elements and return list
    private static void getChildElementNames(XmlSchemaElement element) {

        // Get the type of the element
        XmlSchemaType elementType = element != null ? element.getSchemaType() : null;

        // Confirm if the element is of Complex type
        if (elementType instanceof XmlSchemaComplexType) {
            // Get all particles associated with that element Type
            XmlSchemaParticle allParticles = ((XmlSchemaComplexType) elementType).getParticle();

            // Check particle belongs to which type
            if (allParticles instanceof XmlSchemaSequence) {
                // System.out.println("Sequence Schema Type");
                final XmlSchemaSequence xmlSchemaSequence = (XmlSchemaSequence) allParticles;
                final List<XmlSchemaSequenceMember> items = xmlSchemaSequence.getItems();

                items.forEach((item) -> {
                    XmlSchemaElement itemElements = (XmlSchemaElement) item;
                    schemaElements.add(itemElements);
                    addChild(element.getQName(), itemElements);
                    // Call method recursively to get all subsequent element
                    getChildElementNames(itemElements);
                    schemaElements = new ArrayList<XmlSchemaElement>();
                });

            }
        }
    }

    // Add child elements based on its parent
    private static void addChild(QName qName, XmlSchemaElement child) {
        List<XmlSchemaElement> values = xsdElements.get(qName);
        if (values == null) {
            values = new ArrayList<XmlSchemaElement>();
        }
        values.add(child);
        xsdElements.put(qName, values);
    }
}

Solution

  • After working for some time on the Apache XMLSchema Core library in Java following is my observation.

    There is no way to get the immediate parent directly using the library you can get the information related to the current element and its children from the XmlSchemaElement.