2 Stimmen

Problem bei der Validierung gegen eine XSD mit Java5

Ich versuche, einen Atom-Feed mit Java 5 (JRE 1.5.0 Update 11) zu validieren. Der Code, den ich habe, funktioniert ohne Probleme in Java 6, schlägt aber fehl, wenn er in Java 5 mit einer

org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'xml:base' to a(n) 'attribute declaration' component.

Ich glaube, ich erinnere mich, etwas über die Version von Xerces gebündelt mit Java 5 mit einigen Problemen mit einigen Schemas zu lesen, aber ich kann nicht die Problemumgehung finden. Ist das ein bekanntes Problem? Habe ich einen Fehler in meinem Code?

public static void validate() throws SAXException, IOException {
    List<Source> schemas = new ArrayList<Source>();
    schemas.add(new StreamSource(AtomValidator.class.getResourceAsStream("/atom.xsd")));
    schemas.add(new StreamSource(AtomValidator.class.getResourceAsStream("/dc.xsd")));

    // Lookup a factory for the W3C XML Schema language
    SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");

    // Compile the schemas.
    Schema schema = factory.newSchema(schemas.toArray(new Source[schemas.size()]));
    Validator validator = schema.newValidator();

    // load the file to validate
    Source source = new StreamSource(AtomValidator.class.getResourceAsStream("/sample-feed.xml"));

    // check the document
    validator.validate(source);
}

Update : Ich habe die folgende Methode ausprobiert, aber ich habe immer noch das gleiche Problem, wenn ich Xerces 2.9.0 verwende. Ich habe auch versucht, xml.xsd zur Liste der Schemata hinzuzufügen (da xml:base in xml.xsd definiert ist), aber dieses Mal habe ich

Exception in thread "main" org.xml.sax.SAXParseException: schema_reference.4: Failed to read schema document 'null', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.

Update 2: Ich habe versucht, einen Proxy mit den VM-Argumenten zu konfigurieren -Dhttp.proxyHost=<proxy.host.com> -Dhttp.proxyPort=8080 und jetzt funktioniert es. Ich werde versuchen, von zu Hause aus eine "richtige Antwort" zu geben.

und sorry, ich kann nicht als Kommentar antworten: aus Sicherheitsgründen ist XHR bei der Arbeit deaktiviert ...

3voto

Arjan Punkte 21308

In der Tat wurde erwähnt, dass die von Sun bereitgestellte SchemaFactory in Java 5 Probleme bereitet.

Also: Haben Sie Xerces selbst in Ihr Projekt einbezogen?

Nachdem Sie Xerces eingebunden haben, müssen Sie sicherstellen, dass es verwendet wird. Wenn Sie es hardcodieren möchten (als Minimalanforderung würden Sie wahrscheinlich eine Datei mit Anwendungseigenschaften verwenden, um den folgenden Code zu aktivieren und auszufüllen):

String schemaFactoryProperty = 
  "javax.xml.validation.SchemaFactory:" + XMLConstants.W3C_XML_SCHEMA_NS_URI;

System.setProperty(schemaFactoryProperty,
   "org.apache.xerces.jaxp.validation.XMLSchemaFactory");

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

Wenn Sie nicht hart kodieren wollen, oder wenn Ihr problematischer Code in einer Bibliothek eines Drittanbieters enthalten ist, die Sie nicht ändern können, setzen Sie ihn auf die java Befehlszeile oder Umgebungsoptionen. Zum Beispiel (natürlich in einer Zeile):

set JAVA_OPTS = 
  "-Djavax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema
  =org.apache.xerces.jaxp.validation.XMLSchemaFactory"

Übrigens: Abgesehen davon, dass die von Sun mitgelieferte SchemaFactory-Implementierung Probleme macht (etwas wie com.sun.org.apache.xerces.internal.jaxp.validation.xs.schemaFactoryImpl ), scheint es auch, dass die "Entdeckung" von Nicht-JDK-Implementierungen in dieser Version fehlschlägt. Wenn ich es richtig verstehe, dann würde normalerweise nur das Einbinden von Xerces in der Tat SchemaFactory#neueInstanz diese eingebundene Bibliothek finden und ihr den Vorrang vor der Sun-Implementierung geben. Meines Wissens schlägt das auch in Java 5 fehl, so dass die obige Konfiguration erforderlich ist.

1voto

Arjan Punkte 21308

Ich habe versucht, einen Proxy mit den VM-Argumenten zu konfigurieren -Dhttp.proxyHost=<proxy.host.com> -Dhttp.proxyPort=8080 und jetzt funktioniert es.

Ah, das habe ich nicht gewusst xml.xsd ist in der Tat diejenige, auf die verwiesen wird als http://www.w3.org/2001/xml.xsd oder so ähnlich. Das sollte uns lehren, immer auch einige XML- und XSD-Fragmente anzuzeigen ;-)

Gehe ich also recht in der Annahme, dass Sie 1.) zur Behebung des Java 5-Problems immer noch Xerces einbinden und die Systemeigenschaft festlegen mussten, und dass Sie 2.) nicht über xml.xsd lokal verfügbar?

Bevor Sie Ihre Lösung gefunden haben, haben Sie versucht, mit getResource statt getResourceAsStream , um zu sehen, ob die Ausnahme Ihnen dann mehr Details gezeigt hätte?

Wenn Sie tatsächlich eine xml.xsd verfügbar (also: wenn getResource tatsächlich eine URL lieferte), dann frage ich mich, was Xerces damals aus dem Internet zu holen versucht hat. Oder haben Sie dieses Schema vielleicht nicht in die Liste aufgenommen, bevor Sie Ihre eigenen Schemata hinzugefügt haben? Die Reihenfolge ist wichtig: Abhängigkeiten müssen zuerst hinzugefügt werden.

Für denjenigen, der seine Frage mit Hilfe der Suche beantwortet: Vielleicht kann man mit einem benutzerdefinierten EntityResolver könnte auch die Quelle des Problems anzeigen (wenn man nur etwas in das Protokoll schreibt und einfach zurückgibt null um Xerces anzuweisen, das Standardverhalten zu verwenden).

0voto

Arjan Punkte 21308

Hmmm, habe gerade deinen "Kommentar" gelesen -- beim Editieren wird man nicht auf neue Antworten aufmerksam gemacht, also wird es Zeit, deinen Chef um ein iPhone oder ein anderes Gerät zu bitten, das direkt mit dem Netz verbunden ist ;-)

Nun, ich nehme an, Sie haben etwas hinzugefügt:

schemas.add(
  new StreamSource(AtomValidator.class.getResourceAsStream("/xml.xsd")));

Wenn ja, ist xml.xsd dann tatsächlich auf dem Klassenpfad zu finden ist? Ich frage mich, ob die getResourceAsStream hat nicht ergeben null in Ihrem Fall, und wie new StreamSource(null) würde dann handeln.

Auch wenn getResourceAsStream hat nicht ergeben null die daraus resultierende StreamSource würde immer noch nicht wissen, woher es geladen wurde, was ein Problem sein kann, wenn man versucht, Referenzen einzubinden. Was also, wenn Sie den Konstruktor StreamSource(String systemId) stattdessen:

schemas.add(new StreamSource(AtomValidator.class.getResource("/atom.xsd")));
schemas.add(new StreamSource(AtomValidator.class.getResource("/dc.xsd")));

Sie können auch Folgendes verwenden StreamSource(InputStream inputStream, String systemId) aber ich kann keinen Vorteil gegenüber den beiden oben genannten Linien erkennen. Die Dokumentation erklärt jedoch, warum die Übergabe der systemId in einem der beiden Konstruktoren gut zu sein scheint:

Mit diesem Konstruktor kann neben dem Eingabestrom auch die SystemID festgelegt werden, wodurch relative URIs verarbeitet werden können.

Gleichermaßen, setSystemId(String systemId) erklärt ein wenig:

Der Systembezeichner ist optional, wenn ein Byte- oder Zeichenstrom vorhanden ist, aber es ist dennoch nützlich, einen anzugeben, da die Anwendung ihn zur Auflösung relativer URIs verwenden und in Fehlermeldungen und Warnungen einbeziehen kann (der Parser versucht nur dann, eine Verbindung zum URI zu öffnen, wenn kein Byte- oder Zeichenstrom angegeben ist).

Wenn das nicht funktioniert, kann Ihnen vielleicht ein benutzerdefinierter Fehlerhandler mehr Details liefern:

ErrorHandlerImpl errorHandler = new ErrorHandlerImpl();
validator.setErrorHandler(errorHandler);
:
:
validator.validate(source);

if(errorHandler.hasErrors()){
    LOG.error(errorHandler.getMessages());
    throw new [..];
}
if(errorHandler.hasWarnings()){
    LOG.warn(errorHandler.getMessages());
}

...unter Verwendung des folgenden ErrorHandlers, um die Validierungsfehler zu erfassen und das Parsing so weit wie möglich fortzusetzen:

import org.xml.sax.helpers.DefaultHandler;
private class ErrorHandlerImpl extends DefaultHandler{
    private String messages = "";
    private boolean validationError = false;
    private boolean validationWarning = false;

    public void error(SAXParseException exception) throws SAXException{
        messages += "Error: " + exception.getMessage() + "\n";
        validationError = true;
    }

    public void fatalError(SAXParseException exception) throws SAXException{
        messages += "Fatal: " + exception.getMessage();
        validationError = true;
    }

    public void warning(SAXParseException exception) throws SAXException{
        messages += "Warn: " + exception.getMessage();
        validationWarning = true;
    }

    public boolean hasErrors(){
        return validationError;
    }

    public boolean hasWarnings(){
        return validationWarning;
    }

    public String getMessages(){
        return messages;
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X