简体   繁体   中英

XML validation against xsd's in Java

Issue: We have several services that generate a fair amount of XML via XSLT. We don't have any XSD's. I have taken the time to create the XSD's and want to confirm they are correct. Currently I am attempting to verify that the XSD and the XML are validate correctly.

Problem: I have an xsd(common.xsd) that is imported into all the xsd's. It is not publicly hosted yet, so only recently I found putting the full path of the common.xsd in the AccountList.xsd I was able to get further. I am now receiving the following:

org.xml.sax.SAXParseException; lineNumber: 9; columnNumber: 70; s4s-att-invalid-value: Invalid attribute value for 'type' in element 'element'. Recorded reason: UndeclaredPrefix: Cannot resolve 'common:response' as a QName: the prefix 'common' is not declared.

I am at a loss. I cannot find an example that has been asked in forums or a source code snippet that gets a success. I'd appreciate any assistance in getting this to successfully validate my xml.

common.xsd

<xs:schema  version="1.0" elementFormDefault="qualified" attributeFormDefault="unqualified"
        xmlns="http://www.myorg.com/xsd/gen_fin"
        xmlns:xs="http://www.w3.org/2001/XMLSchema" 
        targetNamespace="http://www.myorg.com/xsd/gen_fin">
    <xs:complexType name="response">
        <xs:sequence>
            <xs:element name="code" type="xs:string"/>
            <xs:element name="description" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

AccountList.xsd

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>

<xs:schema  version="1.0" elementFormDefault="qualified" attributeFormDefault="unqualified"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:xs="http://www.w3.org/2001/XMLSchema"
            xmlns:tns="http://www.myorg.com/xsd/accList"
            targetNamespace="http://www.myorg.com/xsd/accList"
            xmlns:common="http://www.myorg.com/xsd/gen_fin">
    <xs:import namespace="http://www.myorg.com/xsd/gen_fin" 
               schemaLocation="/home/me/dev/projects/svn/myorg/xsd/src/main/resources/bg/gen_resp/common.xsd"/>

    <xs:element name="fundamo">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="response" type="common:response" minOccurs="1" maxOccurs="1"/>
                <xs:element name="transaction" type="tns:transaction" minOccurs="0" maxOccurs="1"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="transaction">
        <xs:sequence>
            <xs:element name="transactionRef" type="xs:string"/>
            <xs:element name="dateTime" type="xs:string"/>
            <xs:element name="userName" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

Test.java

final InputStream commonXsdStream = getXsd(BG_GEN_RESP_XSD_PATH, COMMON);

ClassPathResource fullXsdListing = new ClassPathResource(BG_GEN_RESP_XSD_PATH);

File[] allXsds = fullXsdListing.getFile().listFiles();

for (File currentXsd : allXsds) {
    final int filenameLength = currentXsd.getName().length();
    final String filenameSanExt = currentXsd.getName().substring(0, filenameLength - 4);

    if (!IGNORE.contains(filenameSanExt)) {
        final InputStream xsltStream = getXslt(BG_GEN_RESP_XSLT_PATH, filenameSanExt);
        final InputStream xsdStream = getXsd(BG_GEN_RESP_XSD_PATH, filenameSanExt);

        TransformerFactory xmlTransformer = TransformerFactory.newInstance();
        Templates xsltTemplate = xmlTransformer.newTemplates(new StreamSource(xsltStream));
        final XSLToXMLConvertor converter = new XSLToXMLConvertor();
        String generatedXml = converter.getXML(inputData, xsltTemplate);

        LOG.info(generatedXml);

        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = schemaFactory.newSchema(lnew StreamSource(xsdStream));

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

        /*
        DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
        docBuilderFactory.setNamespaceAware(true);
        docBuilderFactory.setValidating(true);

        DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
        docBuilder.parse(new InputSource(new ByteArrayInputStream(generatedXml.getBytes("utf-8"))));
        */
        }
    }
}

It's usually a good idea to have a namespace and targetNamespace defined, although as Petru Gardea pointed out, not strictly necessary. Here's a combination that absolutely works:

AccountList.xsd

<xs:schema
    version="1.0"
    elementFormDefault="qualified"
    attributeFormDefault="unqualified"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:tns="http://www.myorg.com/xsd/accList"
    targetNamespace="http://www.myorg.com/xsd/accList"
    xmlns:common="http://www.myorg.com/xsd/gen_fin">

    <xs:import namespace="http://www.myorg.com/xsd/gen_fin" schemaLocation="common.xsd" />

    <xs:element name="fundamo">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="response" type="common:response"
                    minOccurs="1" maxOccurs="1" />
                <xs:element name="transaction" type="tns:transaction"
                    minOccurs="0" maxOccurs="1" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="transaction">
        <xs:sequence>
            <xs:element name="transactionRef" type="xs:string" />
            <xs:element name="dateTime" type="xs:string" />
            <xs:element name="userName" type="xs:string" />
        </xs:sequence>
    </xs:complexType>
</xs:schema>

common.xsd

<xs:schema
    version="1.0"
    elementFormDefault="qualified"
    attributeFormDefault="unqualified"
    xmlns="http://www.myorg.com/xsd/gen_fin"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://www.myorg.com/xsd/gen_fin">

    <xs:complexType name="response">
        <xs:sequence>
            <xs:element name="code" type="xs:string" />
            <xs:element name="description" type="xs:string" />
        </xs:sequence>
    </xs:complexType>
</xs:schema>

NewFile.xml (based on that schema):

<tns:fundamo xmlns:p="http://www.myorg.com/xsd/gen_fin"
    xmlns:tns="http://www.myorg.com/xsd/accList" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.myorg.com/xsd/accList AccountList.xsd ">
    <tns:response>
        <p:code>p:code</p:code>
        <p:description>p:description</p:description>
    </tns:response>
</tns:fundamo>

ValidateXml.java:

import java.io.File;
import java.io.IOException;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

public class ValidateXml {

    /**
     * @param args
     */
    public static void main(String[] args) {
        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        try {
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            documentBuilderFactory.setNamespaceAware(true);
            DocumentBuilder parser = documentBuilderFactory.newDocumentBuilder();
            Document document = parser.parse(new File("NewFile.xml"));

            Schema schema = schemaFactory.newSchema(new File("AccountList.xsd"));
            Validator validator = schema.newValidator();

            validator.validate(new DOMSource(document));
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

You error related to "cannot find the declaration of element" is usually related to the XML document not being namespace-aware. Verify that your path to both XSDs is correct, and go back to the block of code where you build an XML document that is namespace-aware.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM