如何通过Java(J2SE)解析WSDL并列出服务及参数(含必填/可选)
Absolutely! You’ve got a great question—parsing a WSDL in Java (J2SE) to extract web services, their operations, and parameter requirements (required vs optional) is totally doable, and there are a few solid approaches depending on whether you want to use third-party libraries or stick to pure J2SE. Let’s break them down:
Apache CXF provides a robust, easy-to-use API that handles both WSDL parsing and XSD schema resolution out of the box. This saves you from manually handling namespace complexities and schema lookups.
Step 1: Add Dependencies
If using Maven, include these in your pom.xml:
<dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-core</artifactId> <version>3.6.2</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>3.6.2</version> </dependency>
Step 2: Parse WSDL and Extract Details
Here’s a complete example that lists services, operations, and marks required parameters:
import org.apache.cxf.wsdl.WSDLManager; import org.apache.ws.commons.schema.XmlSchema; import org.apache.ws.commons.schema.XmlSchemaElement; import org.apache.ws.commons.schema.XmlSchemaSequence; import javax.wsdl.*; import javax.xml.namespace.QName; import java.net.URL; import java.util.Map; public class CxfWsdlParser { public static void main(String[] args) throws Exception { String wsdlUrl = "https://com.provider.soap/services/travel?WSDL"; URL url = new URL(wsdlUrl); // Initialize CXF's WSDL manager WSDLManager manager = WSDLManager.newInstance(); Definition wsdlDefinition = manager.getDefinition(url); // Iterate over all services in the WSDL Map<QName, Service> services = wsdlDefinition.getServices(); for (Map.Entry<QName, Service> serviceEntry : services.entrySet()) { Service service = serviceEntry.getValue(); System.out.println("\n=== Web Service: " + service.getQName().getLocalPart() + " ==="); // Iterate over ports in the service Map<QName, Port> ports = service.getPorts(); for (Port port : ports.values()) { Binding binding = port.getBinding(); BindingOperations bindingOperations = binding.getBindingOperations(); // Iterate over each operation in the port for (BindingOperation bindingOp : bindingOperations) { Operation operation = bindingOp.getOperation(); System.out.println("\n--- Operation: " + operation.getName() + " ---"); // Process input parameters Input input = operation.getInput(); if (input != null) { Message inputMessage = input.getMessage(); Map<QName, Part> inputParts = inputMessage.getParts(); System.out.println("Input Parameters:"); for (Part part : inputParts.values()) { if (part.getElementName() != null) { // Resolve the schema element to check requirement status XmlSchema schema = manager.getSchema(wsdlDefinition, part.getElementName().getNamespaceURI()); XmlSchemaElement element = schema.getElementByName(part.getElementName()); if (element != null) { // Required if minOccurs is 1 (default) or higher; optional if minOccurs=0 boolean isRequired = element.getMinOccurs() == null || element.getMinOccurs() >= 1; String status = isRequired ? "*Required*" : "Optional"; System.out.println("- " + part.getName() + ": " + status); // Parse child elements if the parameter is a complex type if (element.getSchemaType() instanceof XmlSchemaSequence) { XmlSchemaSequence sequence = (XmlSchemaSequence) element.getSchemaType(); for (XmlSchemaElement childElement : sequence.getItems()) { boolean childRequired = childElement.getMinOccurs() == null || childElement.getMinOccurs() >= 1; String childStatus = childRequired ? "*Required*" : "Optional"; System.out.println(" - " + childElement.getName() + ": " + childStatus); } } } } } } // You can add similar logic to process output messages if needed } } } } }
WSDL4J is a lightweight, dedicated library for parsing WSDL files, but it doesn’t handle XSD schema resolution automatically. You’ll need to add extra code to check parameter requirements.
Step 1: Add Dependency
<dependency> <groupId>wsdl4j</groupId> <artifactId>wsdl4j</artifactId> <version>1.6.3</version> </dependency>
Step 2: Basic WSDL Parsing Example
This code extracts service/operation details, but you’ll need to manually parse associated XSD files to check required parameters:
import javax.wsdl.*; import javax.wsdl.factory.WSDLFactory; import javax.wsdl.xml.WSDLReader; import javax.xml.namespace.QName; import java.net.URL; import java.util.Map; public class Wsdl4jParser { public static void main(String[] args) throws Exception { String wsdlUrl = "https://com.provider.soap/services/travel?WSDL"; URL url = new URL(wsdlUrl); WSDLFactory factory = WSDLFactory.newInstance(); WSDLReader reader = factory.newWSDLReader(); reader.setFeature("javax.wsdl.verbose", false); reader.setFeature("javax.wsdl.importDocuments", true); Definition definition = reader.readWSDL(null, url.toString()); // Iterate over services Map<QName, Service> services = definition.getServices(); for (Service service : services.values()) { System.out.println("\n=== Web Service: " + service.getQName().getLocalPart() + " ==="); // Iterate over ports Map<QName, Port> ports = service.getPorts(); for (Port port : ports.values()) { Binding binding = port.getBinding(); BindingOperations bindingOps = binding.getBindingOperations(); for (BindingOperation bindingOp : bindingOps) { Operation operation = bindingOp.getOperation(); System.out.println("\n--- Operation: " + operation.getName() + " ---"); // Process input parameters Input input = operation.getInput(); if (input != null) { Message inputMsg = input.getMessage(); Map<QName, Part> parts = inputMsg.getParts(); System.out.println("Input Parameters:"); for (Part part : parts.values()) { System.out.println("- " + part.getName() + ": (Check associated XSD for required status)"); } } } } } } }
If you can’t use external libraries, you can parse the WSDL as a regular XML document using Java’s built-in DOM/SAX/StAX parsers. This requires handling namespaces and schema lookups manually, so it’s more verbose but self-contained.
Example with DOM Parser
import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.net.URL; public class ManualWsdlParser { public static void main(String[] args) throws Exception { String wsdlUrl = "https://com.provider.soap/services/travel?WSDL"; URL url = new URL(wsdlUrl); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(url.openStream()); // Extract all services NodeList serviceNodes = doc.getElementsByTagNameNS("http://schemas.xmlsoap.org/wsdl/", "service"); for (int i = 0; i < serviceNodes.getLength(); i++) { Element serviceElement = (Element) serviceNodes.item(i); String serviceName = serviceElement.getAttribute("name"); System.out.println("\n=== Web Service: " + serviceName + " ==="); // Extract ports in the service NodeList portNodes = serviceElement.getElementsByTagNameNS("http://schemas.xmlsoap.org/wsdl/", "port"); for (int j = 0; j < portNodes.getLength(); j++) { Element portElement = (Element) portNodes.item(j); String portName = portElement.getAttribute("name"); String bindingName = portElement.getAttribute("binding").split(":")[1]; System.out.println("\nPort: " + portName + " (Binding: " + bindingName + ")"); // Find matching binding NodeList bindingNodes = doc.getElementsByTagNameNS("http://schemas.xmlsoap.org/wsdl/", "binding"); for (int k = 0; k < bindingNodes.getLength(); k++) { Element bindingElement = (Element) bindingNodes.item(k); if (bindingElement.getAttribute("name").equals(bindingName)) { // Extract operations NodeList operationNodes = bindingElement.getElementsByTagNameNS("http://schemas.xmlsoap.org/wsdl/", "operation"); for (int l = 0; l < operationNodes.getLength(); l++) { Element operationElement = (Element) operationNodes.item(l); String operationName = operationElement.getAttribute("name"); System.out.println("\n--- Operation: " + operationName + " ---"); // Process input parameters Element inputElement = (Element) operationElement.getElementsByTagNameNS("http://schemas.xmlsoap.org/wsdl/", "input").item(0); if (inputElement != null) { String inputMsgName = inputElement.getAttribute("message").split(":")[1]; NodeList messageNodes = doc.getElementsByTagNameNS("http://schemas.xmlsoap.org/wsdl/", "message"); for (int m = 0; m < messageNodes.getLength(); m++) { Element messageElement = (Element) messageNodes.item(m); if (messageElement.getAttribute("name").equals(inputMsgName)) { NodeList partNodes = messageElement.getElementsByTagNameNS("http://schemas.xmlsoap.org/wsdl/", "part"); System.out.println("Input Parameters:"); for (int n = 0; n < partNodes.getLength(); n++) { Element partElement = (Element) partNodes.item(n); String partName = partElement.getAttribute("name"); String elementQName = partElement.getAttribute("element"); if (!elementQName.isEmpty()) { // Resolve element in embedded XSD schema NodeList typesNodes = doc.getElementsByTagNameNS("http://schemas.xmlsoap.org/wsdl/", "types"); if (typesNodes.getLength() > 0) { Element typesElement = (Element) typesNodes.item(0); NodeList schemaNodes = typesElement.getElementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "schema"); for (int p = 0; p < schemaNodes.getLength(); p++) { Element schemaElement = (Element) schemaNodes.item(p); String targetNs = schemaElement.getAttribute("targetNamespace"); String elementName = elementQName.split(":")[1]; NodeList elementNodes = schemaElement.getElementsByTagNameNS(targetNs, elementName); if (elementNodes.getLength() > 0) { Element paramElement = (Element) elementNodes.item(0); String minOccurs = paramElement.getAttribute("minOccurs"); boolean isRequired = minOccurs.isEmpty() || Integer.parseInt(minOccurs) >= 1; String status = isRequired ? "*Required*" : "Optional"; System.out.println("- " + partName + ": " + status); } } } } else { System.out.println("- " + partName + ": (Type-based, check XSD for constraints)"); } } } } } } } } } } } }
- A parameter is required if its XSD element has
minOccurs="1"(this is the default if the attribute isn’t specified). - A parameter is optional if its XSD element has
minOccurs="0". - For complex types (parameters with child elements), you’ll need to check each child element’s
minOccursattribute individually, as shown in the CXF example.
Whichever method you choose, Apache CXF is the most efficient and least error-prone option since it handles most of the low-level parsing and schema resolution for you.
内容的提问来源于stack exchange,提问作者Anandhakrishnan

