- PR -

DOCTYPE宣言がないXMLを外部DTDを使用してparseする方法

1
投稿者投稿内容
AC
会議室デビュー日: 2004/04/15
投稿数: 18
投稿日時: 2004-05-27 15:53
Xerces、またはJAXPを使用してDOCTYPE宣言がないXMLに対して外部DTDを使用してparseする方法はあるのでしょうか?
「外部 DTD DOCTYPE宣言がない XML」をキーにしてぐぐって見ましたが見つかりませんでした。
ふうた
大ベテラン
会議室デビュー日: 2001/08/23
投稿数: 198
お住まい・勤務地: 岡山
投稿日時: 2004-05-27 18:45
Xerces2のAPIDOCを見ていると、こんなのがありました。
org.apache.xerces.parsers.DOMParser に setDTDSource というメソッドがあります。
http://xml.apache.org/xerces2-j/javadocs/xerces2/org/apache/xerces/parsers/DOMParser.html
(正確には、setDTDSourceは、DOMParserのスーパークラスであるAbstractXMLDocumentParserのメソッドとなります。)

ただし、これも結局、DOCTYPE宣言がないと意味のないメソッドかもしれません。
(ということで、はずしている可能性大です。。。)

また、Xerces2 限定となります。
(ここで引っかかってしまうのかもしれませんが。)

私も気になるので、試してみて結果を報告いただければ幸いです。

[ メッセージ編集済み 編集者: ふうた 編集日時 2004-05-27 19:15 ]
けむ
常連さん
会議室デビュー日: 2003/09/26
投稿数: 40
投稿日時: 2004-05-27 21:23
EntityResolverが使えそうな気がします。
#試していませんが。
けむ
常連さん
会議室デビュー日: 2003/09/26
投稿数: 40
投稿日時: 2004-05-27 22:26
申し訳ありません。
EntityResolverは、DOCTYPE宣言がないと意味がありませんでしたね。

次のような方法で妥当性検証することができました。
1.a.xmlをb.dtdで妥当性検証するものとします。
2.c.xmlを下記の内容で作成します。

<!DOCTYPE hoge [
<!ELEMENT hoge (a.xmlのルート要素)>
<!ENTITY A_XML SYSTEM "a.xml">
<!ENTITY % B_DTD SYSTEM "b.dtd">
%B_DTD;
]>
<hoge>
&A_XML;
</hoge>

3.c.xmlに対してparseする。

もっとスマートにできそうですが、これくらいしか思いつきませんでした。
AC
会議室デビュー日: 2004/04/15
投稿数: 18
投稿日時: 2004-05-28 12:42
引用:

ふうたさんの書き込み (2004-05-27 18:45) より:
Xerces2のAPIDOCを見ていると、こんなのがありました。
org.apache.xerces.parsers.DOMParser に setDTDSource というメソッドがあります。

(省略)

ただし、これも結局、DOCTYPE宣言がないと意味のないメソッドかもしれません。
(ということで、はずしている可能性大です。。。)

また、Xerces2 限定となります。
(ここで引っかかってしまうのかもしれませんが。)

私も気になるので、試してみて結果を報告いただければ幸いです。

<font size=-1>[ メッセージ編集済み 編集者: ふうた 編集日時 2004-05-27 19:15 ]</font>



スミマセン、OracleのOC4Jというアプリケーションサーバ(バージョン不明)に含まれているXercesを使用しているので詳しいバージョンが判らなかったのですがsetDTDSource()というメソッドがないようなのでXerces2じゃないようです(残念
でも勉強がてらXerces2を使用して実現可能かやってみます。結果が出たらまた報告しますので暫くお待ち下さい。

引用:

けむさんの書き込み (2004-05-27 22:26) より:
申し訳ありません。
EntityResolverは、DOCTYPE宣言がないと意味がありませんでしたね。

次のような方法で妥当性検証することができました。
1.a.xmlをb.dtdで妥当性検証するものとします。
2.c.xmlを下記の内容で作成します。

<!DOCTYPE hoge [
<!ELEMENT hoge (a.xmlのルート要素)>
<!ENTITY A_XML SYSTEM "a.xml">
<!ENTITY % B_DTD SYSTEM "b.dtd">
%B_DTD;
]>
<hoge>
&A_XML;
</hoge>

3.c.xmlに対してparseする。

もっとスマートにできそうですが、これくらいしか思いつきませんでした。



やっぱり最終的にはこういう方法になってしまいますよね(^^;;

とりあえずXerces2でやってみて結果を報告します。
AC
会議室デビュー日: 2004/04/15
投稿数: 18
投稿日時: 2004-05-28 17:26
http://xml.apache.org/xerces2-j/javadocs/xni/org/apache/xerces/xni/parser/XMLDTDSource.html

DOMParser#setDTDSource(...)メソッドからJavaDocを辿ってみたのですがXMLDTDSourceはclassではなくinterfaceで、且つimplementsしたconcrete classも見つからなかったので今回は諦めました。
# 時間的な制限もあるので。

代りにXMLファイルとDTDファイルを結合して新しいXML Documentを生成してparseし直すサンプルプログラムを作成してみました。
以下サンプルソースです。

コード:
import java.io.*;
import org.apache.xerces.parsers.*;
import org.apache.xml.serialize.*;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;

public class CombineTest {

	public static void main(String[] args) throws Exception {
		// args[0] is XML filename
		// args[1] is DTD filename
		OutputStream out = processXerces(args);
//		OutputStream out = processJAXP(args);
		System.out.println(out.toString());
		
		DOMParser parser = new DOMParser();
		parser.setFeature("http://xml.org/sax/features/validation", true);
		parser.parse(
			new InputSource(
				new ByteArrayInputStream(((ByteArrayOutputStream) out).toByteArray())
			)
		);
	}

	/** Xerces version */
	private static OutputStream processXerces(String[] args) throws Exception {
		DOMParser parser = new DOMParser();
		parser.parse(args[0]);
		Document srcXML = parser.getDocument();

		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		DOMImplementation di = db.getDOMImplementation();
		DocumentType dt
			= di.createDocumentType(
				srcXML.getDocumentElement().getNodeName(),
				null,
				args[1]
			);
		
		Document combined = XMLDocumentFactory.combine(srcXML, dt);
		OutputFormat of = new OutputFormat(combined);
		of.setEncoding("UTF-8");
		of.setStandalone(false);
		of.setIndenting(true);
		
		OutputStream out = new ByteArrayOutputStream();
		XMLSerializer serializer = new XMLSerializer(out, of);
		serializer.asDOMSerializer();
		serializer.serialize(combined.getDocumentElement());
		
		return out;
	}

	/** JAXP version */
	private static OutputStream processJAXP(String[] args) throws Exception {
		DOMResult domresult = new DOMResult();
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer transformer = tf.newTransformer();
		transformer.transform(new StreamSource(new FileInputStream(args[0])), domresult);
		Document srcXML = (Document) domresult.getNode();

		DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		DOMImplementation di = db.getDOMImplementation();
		DocumentType dt
			= di.createDocumentType(
				srcXML.getDocumentElement().getNodeName(),
				null,
				args[1]
			);
		
		Document combined = XMLDocumentFactory.combine(srcXML, dt);

		transformer.setOutputProperty("encoding", "UTF-8");
		transformer.setOutputProperty("standalone", "no");
		transformer.setOutputProperty("indent", "yes");

		OutputStream out = new ByteArrayOutputStream();
		transformer.transform(new DOMSource(combined), new StreamResult(out));
		
		return out;
	}

	/** XML and DTD are combined */
	public static Document combine(Document doc, DocumentType docType)
			throws ParserConfigurationException {
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		DOMImplementation di = db.getDOMImplementation();
		Document combined
			= di.createDocument(
				"",
				doc.getDocumentElement().getNodeName(),
				docType
			);
		
		NodeList nodes = doc.getDocumentElement().getChildNodes();
		for (int i = 0; i < nodes.getLength(); ++i) {
			Node node = combined.importNode(nodes.item(i), true);
			combined.getDocumentElement().appendChild(node);
		}
		
		return combined;
	}
}


1

スキルアップ/キャリアアップ(JOB@IT)