Link to home
Start Free TrialLog in
Avatar of sukhoi35
sukhoi35

asked on

How do I generalise a method to receive variable number of parameter values and further process it?

Hi Experts,
After referring to online samples, I have been successful in building a method which accepts a single XML and XSD as input for schema validation. However, I need to generalise this method to accept a dynamic number of XSD paths, define the StreamSources for every path and use them all in factory.newSchema method/constructor. Can I please get suggestions on how this can be best achieved? I was thinking of passing a string list as a parameter, however, not sure how I can use them to define Streamsrouce iteratively and further use them all in factory.newschema. Thanks.
   public static boolean validateXMLSchema(String xsdPath, String xmlData){
        
        try {        
            
            SchemaFactory factory =
                    SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);            
            StreamSource mainXSD = new StreamSource(new File("C:\\XSDs\\main.xsd"));            

            Schema schema = factory.newSchema(new Source[]{mainXSD});

            Validator validator = schema.newValidator();
            validator.validate(new StreamSource(new StringReader(xmlData)));
        } catch (SAXException | IOException e) {
            System.out.println("Exception: "+e.getMessage());
            return false;
        }
        return true;
    }


Open in new window


Avatar of ste5an
ste5an
Flag of Germany image

The simple approach should be obvious, something like this:

public static boolean validateXMLSchema(List<String> xsdPaths, String xmlData)
{
    Bool result = true;
    try {
        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        xsdPaths.forEach(xsdPath -> {
            StreamSource currentSchemaSource = new StreamSource(new File(xsdPath));
            Schema schema = factory.newSchema(new Source[] { currentSchemaSource });
            Validator validator = schema.newValidator();
            validator.validate(new StreamSource(new StringReader(xmlData)));
        });
    }
    catch (SAXException | IOException e) {
        result = false;
        System.out.println("Exception: "+e.getMessage());
    }

    return result;
}

Open in new window


But you should look into the factory methods and the validator class. Cause it seems like they are already prepared for bulk validation.
public static boolean validateXMLSchema(String xsdPath, String xmlData)

Open in new window


The problem with that is that the second parameter introduces inflexibility. For instance you might not want to pass in the data - for one thing it could be too large to hold in memory. Therefore it would be better to use a resource locator and then an override for the case where you DO just want a String.
I'm not aware of a ready-made pairing of content->schema class, so you could just use parallel collections. I would go for
public static boolean validateXMLSchema(List<URI> schemas, List<URI> contentLocations)

Open in new window

and
public static boolean validateXMLSchema(List<URI> schemas, List<String> contents)

Open in new window

Avatar of sukhoi35
sukhoi35

ASKER

Thank you ste5an for your response. The requirement is to pass a single XML message which would have to be validated for multiple XSDs combined. For example

Schema schema = factory.newSchema(new Source[]{mainXSD1, mainXSD2, mainXSD3});

Validator validator = schema.newValidator();
validator.validate(new StreamSource(new StringReader(xmlData)));

Open in new window

However, the approach you suggested would validate the XML separately for every individual XSD.
for multiple XSDs combined
How would that work - i.e. how would they be combined?
ASKER CERTIFIED SOLUTION
Avatar of ste5an
ste5an
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Sorry if I used the wrong word. For example one of the XSDs I use internally refers to other XSDs using the relative path. However, in some cases I will have to explicitly mention it in validator. For example, I had to include soap1.2.xsd for me to resolve the 'soap-envelope' validation error. This is what I did which fixed the issue.

Schema schema = factory.newSchema(new Source[]{soap1.2XSD, mainXSD }

Open in new window




For example one of the XSDs I use internally refers to other XSDs using the relative path. However, in some cases I will have to explicitly mention it in validator
Now it's getting weird. Why?

Can you rephrase your question and especially describe your actual problem?
Cause the generic method to validate XML against schemata are normally the methods in your library. Thus it sounds like reinventing the weel.
Schema schema = factory.newSchema(new Source[]{soap1.2XSD, mainXSD }

Open in new window

I haven't come across this 'building up' of schemas but if that works for you, then why not?

This is also a possibility of course - more general
public static boolean validateXMLSchema(Source[] schemaParts, Reader xml)

Open in new window

or
public static boolean validateXMLSchema(Source[] schemaParts, Source xml)

Open in new window

Thank you Ste5an for your suggestion. Most likely that is what I am looking for, will give it a try and update the solution. Am a novice in Java, easy things are sometimes hard :)