Java,根据WSDL中嵌入的模式验证XML

5

我有一个包含嵌入式模式的 .wsdl 文件。我想使用该 .wsdl 文件来验证 XML 文件/字符串(就像您验证 .xsd 文件一样)。 模式在 <types> 标记之间。我已经做了以下工作:

public boolean validate(String xmlString) {
    try {
        // Convert to input stream
        InputStream xml = new ByteArrayInputStream(xmlString.getBytes());

        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = schemaFactory.newSchema(new File("wsdl_filepath"));

        // Validate against wsdl
        Validator validator = schema.newValidator();
        validator.validate(new StreamSource (xml));

        // XML Message is valid
        return true;

    } catch (SAXException e) {
        e.printStackTrace();
        return false;

    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }
}

这并不起作用。该验证器仅在针对一个.xsd文件进行验证时有效。我不确定如何修改它以针对嵌入式模式进行验证。
非常感谢您的帮助!

1
你为什么想要这样做?难道你不能先将类型定义复制到某个文件中,然后执行验证吗? - Tirath
我无法从.wsdl文件中提取模式。公司希望将其保留在其中。 - o.o
你为什么要自己进行验证?难道对于“文档”样式,请求/响应不会根据类型定义自动进行验证吗? - Tirath
我对Web服务的工作原理并不是很有经验,仍在学习中。你是说因为它被嵌入了,所以没有必要进行验证吗?我不知道它会自动发生。 - o.o
1
是的。如果你正在处理Document风格的服务,这件事情已经被照顾好了。我们不需要自己操心。你可以通过将WSDL网址放入SOAPUI(Web服务测试工具)中来验证这一点。现在,当你即将触发请求时,只需更改请求XML。也许,添加一个额外的元素或删除一个元素。 - Tirath
谢谢,那个例子非常有帮助! - o.o
2个回答

4

以下是我从wsld中提取模式的方法:

public static Schema makeSchema(String pathToWsdl)
    throws ParserConfigurationException, IOException, SAXException, InstantiationException, IllegalAccessException, ClassNotFoundException {
    // read wsdl document
    File wsdlFile = new File(pathToWsdl);
    DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
    dbFactory.setNamespaceAware(true);
    DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
    Document wsdlDoc = dBuilder.parse(wsdlFile);

    // read namespace declarations from wsdl document, in case they are referred from a schema
    NamedNodeMap attributes = wsdlDoc.getDocumentElement().getAttributes();
    Map<String, String> namespacesFromWsdlDocument = new HashMap<>();
    for (int i = 0; i < attributes.getLength(); i++) {
        Node n = attributes.item(i);
        if (n.getNamespaceURI() != null && n.getNamespaceURI().equals("http://www.w3.org/2000/xmlns/")) {
            namespacesFromWsdlDocument
                .put(n.getLocalName(), n.getNodeValue());
        }
    }

    // read the schema nodes from the wsdl
    NodeList schemas = wsdlDoc.getElementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "schema");
    Map<String, DOMSource> sources = new HashMap<>();
    for (int i = 0; i < schemas.getLength(); i++) {
        // create a document for each schema and copy the source schema
        Document schema = dBuilder.newDocument();
        Element schemaElement = (Element)schema.importNode(schemas.item(i), true);

        // add all non-existing namespace declarations from the wsdl node
        String targetNs = schemaElement.getAttribute("targetNamespace");
        for (Map.Entry<String, String> ns : namespacesFromWsdlDocument.entrySet()) {
            String name = ns.getKey();
            String value = ns.getValue();
            if (schemaElement.getAttributeNodeNS("http://www.w3.org/2000/xmlns/", name) == null) {
                schemaElement.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:" + name, value);
            }
        }

        // map schemas by their target namespace
        schema.appendChild(schemaElement);
        DOMSource domSource = new DOMSource(schema);
        sources.put(targetNs, domSource);
    }

    SchemaFactory factory =
        SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

    // Create a ResourceResolver that can find the correct schema from the map
    DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();

    final DOMImplementationLS domImplementationLS = (DOMImplementationLS) registry.getDOMImplementation("LS");
    factory.setResourceResolver(new LSResourceResolver() {
        @Override public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) {
            Source xmlSource = sources.get(namespaceURI);
            if (xmlSource != null) {
                LSInput input = domImplementationLS.createLSInput();
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                Result outputTarget = new StreamResult(outputStream);
                try {
                    TransformerFactory.newInstance().newTransformer().transform(xmlSource, outputTarget);
                } catch (TransformerException e) {
                    e.printStackTrace();
                }
                InputStream is = new ByteArrayInputStream(outputStream.toByteArray());
                input.setByteStream(is);
                input.setSystemId(systemId);
                return input;
            } else {
                return null;
            }
        }
    });

    // create the schema object from the sources
    return factory.newSchema(sources.values().toArray(new DOMSource[]{}));
}

0

在 @morten 的 答案 上进行扩展,我发现可以使用 JAXB 注释的类生成模式文件,而不是直接从 WSDL 文件中获取模式。当使用此方法时,仍然需要将资源解析器添加到模式工厂中。

private static Schema createSchemaFromType(final Class<?> type) throws Exception {
    final AtomicInteger          sequence            = new AtomicInteger(1);
    final ByteArrayOutputStream  schemasOutputStream = new ByteArrayOutputStream();
    final DocumentBuilderFactory dbFactory           = DocumentBuilderFactory.newInstance();
    dbFactory.setNamespaceAware(true);

    // Generate the schemas from the JAXB annotated classes and put the output in the schemasOutputStream.
    JAXBContext.newInstance(type).generateSchema(new SchemaOutputResolver() {
        @Override
        public Result createOutput(final String namespaceUri, final String suggestedFileName) {
            final Result result = new StreamResult(schemasOutputStream);
            result.setSystemId("sys" + sequence.getAndIncrement());
            return result;
        }
    });

    // The result of the previous operation puts all schemas in a byte array. Transform the byte array output into
    // a string, which will contain a number of different schemas, then split the string to put each individual
    // schema in its own string.
    final byte[]                 schemasOutputBytes           = schemasOutputStream.toByteArray();
    final String                 schemasOutputString          = new String(schemasOutputBytes, StandardCharsets.UTF_8);
    final String                 schemasOutputStringDelimited = schemasOutputString.replace("<?xml", "<<<START OF SCHEMA>>><?xml");
    final String[]               schemaStrings                = schemasOutputStringDelimited.split("<<<START OF SCHEMA>>>");
    final Map<String, DOMSource> schemasSourcesByNamespace    = new HashMap<>();

    // Map the schema documents by their target namespace.
    for (final String schemaString : schemaStrings) {
        if (schemaString.trim().length() > 0) {
            final String               schema                = schemaString.replace("schemaLocation=\".*?\"", "");
            final ByteArrayInputStream schemaInputStream     = new ByteArrayInputStream(schema.getBytes(StandardCharsets.UTF_8));
            final DocumentBuilder      documentBuilder       = dbFactory.newDocumentBuilder();
            final Document             schemaDocument        = documentBuilder.parse(schemaInputStream);
            final Element              schemaElement         = schemaDocument.getDocumentElement();
            final String               schemaTargetNamespace = schemaElement.getAttribute("targetNamespace");
            schemasSourcesByNamespace.put(schemaTargetNamespace, new DOMSource(schemaDocument));
        }
    }

    // Create the schema factory in a way that it can resolve the schemas for all the namespaces previously created.
    final DOMImplementationRegistry domImplementationRegistry = DOMImplementationRegistry.newInstance();
    final DOMImplementationLS       domImplementation         = (DOMImplementationLS) domImplementationRegistry.getDOMImplementation("LS");
    final SchemaFactory             schemaFactory             = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    schemaFactory.setResourceResolver(new LSResourceResolver() {
        @Override
        public LSInput resolveResource(
            final String type,
            final String namespaceUri,
            final String publicId,
            final String systemId,
            final String baseUri
        ) {
            final Source xmlSource = schemasSourcesByNamespace.get(namespaceUri);
            if (xmlSource != null) {
                final LSInput               input        = domImplementation.createLSInput();
                final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                final Result                outputTarget = new StreamResult(outputStream);

                try {
                    transformerFactory.newTransformer().transform(xmlSource, outputTarget);
                } catch (final TransformerException e) {
                    throw new RuntimeException(
                        "Failed to transform schema document for namespace '" + namespaceUri + "' into an " +
                        "output stream due to an unexpected error.",
                        e
                    );
                }

                final InputStream is = new ByteArrayInputStream(outputStream.toByteArray());
                input.setByteStream (is);
                input.setSystemId   (systemId);
                return input;
            } else {
                return null;
            }
        }
    });

    // Create the schema using the schema sources.
    return schemaFactory.newSchema(schemasSourcesByNamespace.values().toArray(new DOMSource[]{}));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接