Problem beim Überprüfen gegen eine XSD mit Java5

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

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

läuft, ich denke, ich erinnere mich, etwas über die Version von Xerces zu lesen, die mit Java 5 gebündelt ist und einige Probleme mit einigen Schemas hat, aber ich kann die Problemumgehung nicht finden. Ist es 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 Methode unten 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 Schemas 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 -Dhttp.proxyHost=<proxy.host.com> -Dhttp.proxyPort=8080 and now it works. I'll try to post a "real answer" from home. zu konfigurieren und jetzt funktioniert es. Ich werde versuchen, eine "echte Antwort" von zu Hause zu posten.

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

Antwort auf "Problem beim Überprüfen gegen eine XSD mit Java5 " 3 von antworten

Tatsächlich haben die Leute die Java 5 Sun erwähnt, vorausgesetzt SchemaFactory gibt Ärger.

Also: Haben Sie Xerces selbst in Ihr Projekt aufgenommen?

Nach dem Einschließen von Xerces müssen Sie sicherstellen, dass es verwendet wird. Wenn Sie es hartcodieren möchten (naja, als minimale Anforderung würden Sie wahrscheinlich einige Anwendungseigenschaften-Datei verwenden, um den folgenden Code zu aktivieren und aufzufü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);

Oder, wenn Sie nicht hardcodieren möchten, oder wenn sich Ihr lästiger Code in einer Bibliothek von Drittanbietern befindet, die Sie nicht ändern können, legen Sie ihn auf die Befehlszeile oder Umgebungsoptionen java command line or environment options. For example (on one line of course): fest. 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 von der Sun-Implementierung, die die SchemaFactory-Implementierung mit Problemen (etwas wie com.sun.org.apache.xerces.internal.jaxp.validation.xs.schemaFactoryImpl), it also seems that the "discovery" of non-JDK implementations fails in that version. If I understand correctly than, normally, just including Xerces would in fact make ) verursacht, scheint es auch, dass die "Entdeckung" von Nicht-JDK-Implementierungen in dieser Version fehlschlägt. Wenn ich richtig verstehe als normalerweise, würde nur die Einbeziehung von Xerces tatsächlich SchemaFactory#newInstance find that included library, and give it precedence over the Sun implementation. To my knowledge, that fails as well in Java 5, making the above configuration required. finden, die Bibliothek enthalten, und ihr Vorrang vor der Sun-Implementierung geben. Meines Wissens schlägt das auch in Java 5 fehl, so dass die obige Konfiguration erforderlich ist.

Hmmm, lesen Sie einfach Ihren "Kommentar" -- Die Bearbeitung warnt die Leute nicht vor neuen Antworten, also Zeit, Ihren Chef nach einem iPhone oder einem anderen Gadget zu fragen, das direkt mit dem Netz verbunden ist ;-)

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

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

Wenn ja, ist xml.xsd actually to be found on the classpath then? I wonder if the dann tatsächlich auf dem Klassenpfad zu finden? Ich frage mich, ob die getResourceAsStream did not yield nicht null in your case, and how in Ihrem Fall ergeben hat, und wie new StreamSource(null) would act then. dann handeln würde.

Auch wenn getResourceAsStream did not yield nicht null, the resulting ergibt, würde das resultierende StreamSource would still not know where it was loaded from, which may be a problem when trying to include references. So, what if you use the constructor immer noch nicht wissen, woher es geladen wurde, was ein Problem beim Versuch sein kann, Referenzen einzuschließen. Also, was ist, wenn Sie stattdessen den Konstruktor StreamSource(String systemId) instead: verwenden:

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

Sie können auch StreamSource(InputStream inputStream, String systemId), but I don't see any advantage over the above two lines. However, the documentation explains why passing the systemId in either of the 2 constructors seems good: verwenden, aber ich sehe keinen Vorteil gegenüber den beiden oben genannten Zeilen. Die Dokumentation erklärt jedoch, warum das Übergeben der systemId in einem der beiden Konstruktoren gut erscheint:

Dieser Konstruktor ermöglicht es, die systemID zusätzlich zum Eingabestream festzulegen, wodurch relative URIs verarbeitet werden können.

Ebenso erklärt setSystemId(String systemId) explains a bit: ein wenig:

Der Systembezeichner ist optional, wenn es einen Byte-Stream oder einen Zeichenstream gibt, aber es ist immer noch nützlich, einen bereitzustellen, da die Anwendung sie verwenden kann, um relative URIs aufzulösen und sie in Fehlermeldungen und Warnungen einschließen kann (der Parser versucht, eine Verbindung zum URI nur zu öffnen, wenn kein Bytestream oder Zeichenstream angegeben ist).

Wenn das nicht klappt, dann kann Ihnen vielleicht ein benutzerdefinierter Fehlerhandler weitere Details geben:

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());
}

... Verwenden des folgenden ErrorHandlers zum Erfassen der Validierungsfehler und weitere Analyse nach Möglichkeit:

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;
    }
}

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

Ah, ich habe nicht gemerkt, dass xml.xsd is in fact the one referenced as in Wirklichkeit diejenige ist, die als http://www.w3.org/2001/xml.xsd or something like that. That should teach us to always show some XML and XSD fragments as well. ;-) oder so ähnlich bezeichnet wird. Das sollte uns lehren, immer auch einige XML- und XSD-Fragmente anzuzeigen. ;-)

Also, bin ich richtig, dass 1.) Um das Java 5-Problem zu beheben, mussten Sie noch Xerces einschließen und die Systemeigenschaft festlegen, und das 2.) Sie hatten xml.xsd available locally? nicht vor Ort?

Bevor Sie Ihre Lösung gefunden haben, haben Sie zufällig versucht, getResource rather than anstelle von getResourceAsStream, to see if the exception would then have showed you some more details? zu verwenden, um zu sehen, ob die Ausnahme Ihnen dann einige weitere Details gezeigt hätte?

Wenn Sie tatsächlich xml.xsd available (so: if zur Verfügung hatten (also: wenn getResource did in fact yield a URL) then I wonder what Xerces was trying to fetch from the internet then. Or maybe you did not add that schema to the list prior to adding your own schemas? The order is important: dependencies must be added first. tatsächlich eine URL ergeben hat), dann frage ich mich, was Xerces damals aus dem Internet holen wollte. Oder haben Sie dieses Schema nicht zur Liste hinzugefügt, bevor Sie eigene Schemas hinzugefügt haben? Die Reihenfolge ist wichtig: Abhängigkeiten müssen zuerst hinzugefügt werden.

Für alle, die seine Frage mit der Suche beantworten: vielleicht mit einem benutzerdefinierten EntityResolver could have indicated the source of the problem as well (if only writing something to the log and just returning null to tell Xerces to use the default behavior). to tell Xerces to use the default behavior). könnte auch die Ursache des Problems angegeben haben (wenn nur etwas in das Protokoll geschrieben und nur null to tell Xerces to use the default behavior). zurückgeben, um Xerces zu sagen, das Standardverhalten zu verwenden).