# XML-Validator erzeugt Fehler



## mmonshausen (6. März 2008)

Hallo,
ich habe ein kniffliches Problem: Ich habe ein Servlet, dass eine WSDL-Datei parsed, daraus ein Eingabe-Formular erstellt in das der Benutzer seine Eingaben machen kann, so dass er Web-Services testen kann. Die Eingaben werden an ein anderes Servlet gesandt, wo ich den Request zusammenbaue. Dort will ich nun auch eine Validierung der Eingaben entsprechend dem Schema in der WSDL-Datei machen.
Zur Validierung setze ich javax.xml.validation.Validator ein. Wenn ich nun den Validator auf meine Nachricht loslasse, so erhalte ich immer den Fehler "org.xml.sax.SAXParseException: 
cvc-complex-type.2.4.d: Invalid content was found starting with element 
'CityName'. No child element is expected at this point."
Der WebService der die Nachricht erhält liefert aber das korrekte Ergebnis zurück, so dass ich nicht glaube das die Nachricht wirklich falsch ist...

Mein Schema sieht (verkürzt) so aus:
<s:schema elementFormDefault='qualified' targetNamespace='http://www.webserviceX.NET' xmlns:s='http://www.w3.org/2001/XMLSchema'>
<s:element name='GetWeather'>
<s:complexType>
<s:sequence>
<s:element maxOccurs='1' minOccurs='0' name='CityName' type='s:string'/>
<s:element maxOccurs='1' minOccurs='0' name='CountryName' type='s:string'/>
</s:sequence>
</s:complexType>
</s:element>
</s:schema>

Mein XML-Dokument so:
<GetWeather xmlns="http://www.webserviceX.NET">
<CountryName>Germany</CountryName>
<CityName>Mannheim</CityName>
</GetWeather>

meine Validator-Methode sieht (verkürzt (z.T. ohne try / catch) so aus:
private boolean validate(String message, String msgSchema)
{
  boolean valid = true;
  Document document = null;
  Validator validator = null;

  // parse an XML document into a DOM tree
  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  // this is an workaround for a bug in JDK 6 and JAX 		    
  dbf.setNamespaceAware(true);
  DocumentBuilder parser = dbf.newDocumentBuilder();
  document = parser.parse(new InputSource(new StringReader(message)));

  //parse the schema
  SchemaFactory factory = SchemaFactory.newInstance(
	  XMLConstants.W3C_XML_SCHEMA_NS_URI);
  Source schemaFile = new StreamSource(new StringReader(msgSchema));
  Schema schema = factory.newSchema(schemaFile);

 // create a Validator instance
 validator = schema.newValidator();

 // try to validate the message
  try { validator.validate(new DOMSource(document)); }
  catch (SAXException e)
  {
	valid = false;
	e.printStackTrace();
  }
}

Kann mir bitte jemand einen Tipp geben, was ich da falsch gemacht habe...

Vielen Dank,

Martin


----------



## Oliver Gierke (6. März 2008)

Bei sequence ist die Reihenfolge wichtig. Nachdem CountryName schon aufgetaucht ist, darf laut deiner XSD nix mehr kommen. Einfach die Elemente im XML vertauschen oder halt das XSD entsprechend abändern.

REINHAUN!

P.S.: Bitte nutz für Quellcode [ java] [ /java] bzw. [ xml] [ /xml], danke!


----------



## mmonshausen (13. März 2008)

Hallo,
danke für den Hinweis! Daran habe ich jetzt gar nicht mehr bei dieser Fehlermeldung gedacht...

Das Problem ist, dass ich an dem Schema nichts ändern kann; ist von der WSDL-Datei vorgegeben.
Die XML-Datei erzeuge ich aus den Eingaben des Benutzers, die er zuvor in das Formular das aus dem WSDL-File erzeugt wurde eingegeben hat. Auf der Seite dieses Formulars und im Request von dem Formular an das zweite Servlet (das das XML-File zusammenbaut) ist die Reihenfolge noch korrekt, aus irgendeinem Grund wird aber in anderer Reihenfolge wieder ausgelesen (und das XML-File erzeugt).

Hier der Code

```
StringBuffer buff2 = new StringBuffer();
Enumeration enums = request.getParameterNames();
while (enums.hasMoreElements())
{
String varName = (String) enums.nextElement();

String content = request.getParameter(varName);
buff2.append("<" + varName + ">" + content + "</" + varName + ">\n");
}
validate(buff2.toString());
```

Die Methode steht in einem Servlet und erhält über POST die Parameter (die in HttpServletRequest request stehen)

Sieht jemand einen logischen Fehler in meinem Coding oder hat eine Idee, wie man es hinbekommen könnte, dass die Variablen-Namen in der richtigen Reihenfolge ausgelesen werden?

Vielen Dank,

Martin


----------



## Oliver Gierke (14. März 2008)

Mach dir doch eine Referenzliste mit den Elementnamen in der richtigen Reihenfolge:


```
private static final List<String> reference = Arrays.asList("CountryName", "CityName");

Map<String, String> paramters = request.getParameterMap();

for (String key : reference) {
  String value = parameters.get(key);

  if (null != value) {
    // erzege das Element
  }
}
```

Entschuldig bitte evtl. enthaltene Methodenfehler o.ä. Hab die API grad nicht bei der Hand. Aber die Idee sollte klar werden.

Ich würde allerdings beim Arbeiten mit WSDL / WebServices definitiv kein XML "von Hand" zusammenklopfen. So spezifizierst du nämlich die Reihenfolge der Elemente usw. (also das was eigentlich im XSD steht) im Code nochmal und musst bei jeder Änderung an dem WSDL den Code umbauen. Ohne WS Framework bzw. nen OX mapper würd ich sowas nicht anfangen.

Gruß
Ollie


----------



## mmonshausen (14. März 2008)

Hallo,
vielen Dank für deine schnelle und umfassende Antwort! Leider hilft mir das nicht wirklich weiter; vielleicht habe ich nicht genug in den Vordergrund gestellt was meine Anwendung macht:

Sie besteht aus zwei Servlets (a und b), der Benutzer (eher der Administrator) übergibt die Adresse auf irgendein (mir unbekanntes) WSDL-File an Servlet A. Ich kann also leider nicht wie vorgeschlagen einfach eine Liste in korrekter Reihenfolge machen (ich kenne die Reihenfolge ja gar nicht im Voraus).
Servlet A erstellt aus dem WSDL-File ein HTML-Formular, in das der Benutzer die entsprechenden Werte eingeben kann um den WebService ausprobieren zu können. Servlet A sendet die Eingaben des Benutzers via POST an Servlet B.
Servlet B erstellt aus diesen Eingaben dann eine korrekte SOAP-Anfrage und sendet sie an den WebService.

Mein Problem ist nun, dass die Reihenfolge auf dem Weg von Servlet A nach Servlet B verloren geht. Wie oben erwähnt, stimmt die Reihenfolge in Servlet A und im Request an Servlet B ist die Reihenfolge auch noch richtig (hab ich durch Umstellung auf GET ausprobiert). Ich suche also faktisch nach einer Lösung die Variablen in korrekter Reihenfolge auszulesen...

Vielen Dank für deine Hilfe,

Martin


----------



## Oliver Gierke (16. März 2008)

Schick halt das WSDL nochmal mit an Servlet B. Dann kannst die Reihenfolge da auslesen. B sollte eh nochmal gegen das XSD im WSDL validieren.

Gruß
Ollie


----------

