Ich habe eine Klasse, die xml von einer Drittanbieter-Quelle entfernt (ich habe keine Kontrolle über den Inhalt). Hier ist das Snippet, das den Befehl munshars:
%Vor% Connections
ist eine klassengenerierte dtd- & gt; xsd- & gt; -Klasse, die xjc verwendet. Das Paket com.optimumlightpath.it.aspenoss.xsd
enthält alle diese Klassen.
Das XML, das ich erhalte, enthält einen relativen Pfad im DOCTYPE. Grundsätzlich enthält str.value
oben:
Dies wird erfolgreich als Java 1.5-Anwendung ausgeführt. Um den obigen Fehler zu vermeiden, musste ich ein ./dtd-Verzeichnis aus dem Projektstamm erstellen und alle dtd-Dateien einschließen (ich bin mir nicht sicher, warum ich das tun musste, aber wir kommen dazu).
Ich habe seitdem einen Webservice auf Tomcat5.5 erstellt, der die oben genannte Klasse verwendet. Ich bekomme [org.xml.sax.SAXParseException: Relative URI "./dtd/Connections.dtd"; can not be resolved without a document URI.]
auf der Unmarshal-Linie. Ich habe versucht, ./dtd in jedem relavant-Ordner (Projektstamm, WebContent, WEB-INF, Tomcat-Arbeitsverzeichnis, usw.) ohne Erfolg zu erstellen.
Frage # 1: Wo kann ich ./dtd finden, damit die Klasse es finden kann, wenn es als Tomcat-Webservice ausgeführt wird? Gibt es irgendeine Tomcat- oder Service-Konfiguration, die ich ausführen muss, um das Verzeichnis zu erkennen?
Frage 2: Warum braucht die Klasse überhaupt die dtd-Datei? Hat es nicht alle Informationen, die es benötigt, um in den Annotationen der dtd- & gt; xsd- & gt; -Klasse zu entpacken? Ich habe viele Artikel gelesen, in denen die Validierung deaktiviert, EntityResource und andere Lösungen eingestellt wurden, aber diese Klasse wird nicht immer als Web-Service bereitgestellt und ich möchte keine zwei Code-Züge haben.
Beim Paralleln aus einem InputStream oder Reader kennt der Parser die systemId (uri / location) des Dokuments nicht, so dass relative Pfade nicht aufgelöst werden können. Es scheint, dass der Parser versucht, Verweise unter Verwendung des aktuellen Arbeitsverzeichnisses aufzulösen, was nur funktioniert, wenn es von der IDE- oder Befehlszeile ausgeführt wird. Um dieses Verhalten zu übergehen und die Auflösung selbst vorzunehmen, müssen Sie ein EntityResolver
implementieren, wie Blaise Doughan erwähnt.
Nach einigem Experimentieren habe ich eine Standardmethode gefunden, dies zu tun. Sie müssen von SAXSource
abmaren, was wiederum aus einem XMLReader
und einem InputSource
besteht. In diesem Beispiel befindet sich das dtd neben der annotierten Klasse und kann daher im Klassenpfad gefunden werden.
Haupt.java
%Vor%Root.java
%Vor%root.dtd
%Vor%Frage # 2: Warum ist die Klasse überhaupt? brauche die dtd-Datei an erster Stelle?
Es ist nicht die JAXB-Implementierung, die nach der DTD sucht, es ist der zugrundeliegende Parser.
Frage 1: Wo finde ich ./dtd damit die Klasse es finden kann, wenn sie ausgeführt wird als Tomcat Webservice?
Ich bin mir nicht sicher, aber unten werde ich einen Weg zeigen, wie Sie das mit dem MOXy JAXB Implementierung (ich bin der technische Leiter), die in mehreren Umgebungen funktioniert.
Lösungsvorschlag
Erstellen Sie einen EntityResolver, der die DTD aus dem Klassenpfad lädt. Auf diese Weise können Sie die DTD mit Ihrer Anwendung verpacken, und Sie werden immer wissen, wo sie ist, unabhängig von der Implementierungsumgebung.
%Vor%Anschließend können Sie mithilfe der MOXy JAXB-Implementierung in die zugrunde liegende Implementierung verzweigen und den EntityResolver festlegen.
%Vor% Hier ist eine weitere Variation der Antworten, die bereits mit der EntityResolver
-Schnittstelle gegeben wurden. Meine Situation bestand darin, relative externe XML-Entitäten von einer XML-Datei zu einer anderen in einer Ordnerhierarchie aufzulösen. Der Parameter für den Konstruktor unten ist der XML-Ordner "working", nicht das Arbeitsverzeichnis des Prozesses.