このファイルを適切にトランスコードするには、Java の XML API を使用する必要があります。これを行うにはいくつかの方法がありますが、ここでは javax.xml.transform パッケージを使用したソリューションを示します。まず、ドキュメントで参照されている djnml-1.0b.dtd ファイルが本当に必要です (エンティティ参照が含まれている場合)。これがないため、このソリューションでは、Trangを使用して、提供された入力から生成された DTD を使用します。
<?xml encoding="UTF-8"?>
<!ELEMENT doc (djnml)>
<!ATTLIST doc
xmlns CDATA #FIXED ''
destination NMTOKEN #REQUIRED
distId NMTOKEN #REQUIRED
md5 CDATA #REQUIRED
msize CDATA #REQUIRED
sysId NMTOKEN #REQUIRED
transmission-date NMTOKEN #REQUIRED>
<!ELEMENT djnml (head,body)>
<!ATTLIST djnml
xmlns CDATA #FIXED ''
docdate CDATA #REQUIRED
product NMTOKEN #REQUIRED
publisher NMTOKEN #REQUIRED
seq CDATA #REQUIRED
xml:lang NMTOKEN #REQUIRED>
<!ELEMENT head (copyright,docdata)>
<!ATTLIST head
xmlns CDATA #FIXED ''>
<!ELEMENT body (headline,text)>
<!ATTLIST body
xmlns CDATA #FIXED ''>
<!ELEMENT copyright EMPTY>
<!ATTLIST copyright
xmlns CDATA #FIXED ''
holder CDATA #REQUIRED
year CDATA #REQUIRED>
<!ELEMENT docdata (djn)>
<!ATTLIST docdata
xmlns CDATA #FIXED ''>
<!ELEMENT headline (#PCDATA)>
<!ATTLIST headline
xmlns CDATA #FIXED ''
brand-display NMTOKEN #REQUIRED
prefix CDATA #REQUIRED>
<!ELEMENT text (pre,p+)>
<!ATTLIST text
xmlns CDATA #FIXED ''>
<!ELEMENT djn (djn-newswires)>
<!ATTLIST djn
xmlns CDATA #FIXED ''>
<!ELEMENT pre EMPTY>
<!ATTLIST pre
xmlns CDATA #FIXED ''>
<!ELEMENT p (#PCDATA)>
<!ATTLIST p
xmlns CDATA #FIXED ''>
<!ELEMENT djn-newswires (djn-press-cutout,djn-urgency,djn-mdata)>
<!ATTLIST djn-newswires
xmlns CDATA #FIXED ''
news-source NMTOKEN #REQUIRED
origin NMTOKEN #REQUIRED
service-id NMTOKEN #REQUIRED>
<!ELEMENT djn-press-cutout EMPTY>
<!ATTLIST djn-press-cutout
xmlns CDATA #FIXED ''>
<!ELEMENT djn-urgency (#PCDATA)>
<!ATTLIST djn-urgency
xmlns CDATA #FIXED ''>
<!ELEMENT djn-mdata (djn-coding)>
<!ATTLIST djn-mdata
xmlns CDATA #FIXED ''
accession-number CDATA #REQUIRED
brand NMTOKEN #REQUIRED
display-date NMTOKEN #REQUIRED
hot NMTOKEN #REQUIRED
original-source NMTOKEN #REQUIRED
page-citation CDATA #REQUIRED
retention NMTOKEN #REQUIRED
temp-perm NMTOKEN #REQUIRED>
<!ELEMENT djn-coding (djn-company,djn-isin,djn-industry,djn-subject,
djn-market,djn-product,djn-geo)>
<!ATTLIST djn-coding
xmlns CDATA #FIXED ''>
<!ELEMENT djn-company (c)>
<!ATTLIST djn-company
xmlns CDATA #FIXED ''>
<!ELEMENT djn-isin (c)>
<!ATTLIST djn-isin
xmlns CDATA #FIXED ''>
<!ELEMENT djn-industry (c)+>
<!ATTLIST djn-industry
xmlns CDATA #FIXED ''>
<!ELEMENT djn-subject (c)+>
<!ATTLIST djn-subject
xmlns CDATA #FIXED ''>
<!ELEMENT djn-market (c)+>
<!ATTLIST djn-market
xmlns CDATA #FIXED ''>
<!ELEMENT djn-product (c)+>
<!ATTLIST djn-product
xmlns CDATA #FIXED ''>
<!ELEMENT djn-geo (c)+>
<!ATTLIST djn-geo
xmlns CDATA #FIXED ''>
<!ELEMENT c (#PCDATA)>
<!ATTLIST c
xmlns CDATA #FIXED ''>
このファイルを「djnml-1.0b.dtd」に書き出した後、XSLT を使用して恒等変換を作成する必要があります。TransformerFactory の newTransformer() メソッドでこれを行うことができますが、この変換の結果は明確に指定されていません。XSLT を使用すると、よりクリーンな結果が得られます。このファイルを恒等変換として使用します。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="no"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
上記の XSLT ファイルを「identity.xsl」として保存します。DTD と恒等変換ができたので、次のコードを使用してファイルをトランスコードできます。
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
...
File inFile = new File("20121114000606JA.xml");
File outputFile = new File("test.xml");
final File dtdFile = new File("djnml-1.0b.dtd");
File identityFile = new File("identity.xsl");
final List<Closeable> closeables = new ArrayList<Closeable>();
try {
// We are going to use a SAXSource for input, so that we can specify the
// location of the DTD with an EntityResolver.
InputStream in = new FileInputStream(inFile);
closeables.add(in);
InputSource fileSource = new InputSource();
fileSource.setByteStream(in);
fileSource.setSystemId(inFile.toURI().toString());
SAXSource source = new SAXSource();
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setEntityResolver(new EntityResolver() {
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
if (systemId != null && systemId.endsWith("/djnml-1.0b.dtd")) {
InputStream dtdIn = new FileInputStream(dtdFile);
closeables.add(dtdIn);
InputSource inputSource = new InputSource();
inputSource.setByteStream(dtdIn);
inputSource.setEncoding("UTF-8");
return inputSource;
}
return null;
}
});
source.setXMLReader(reader);
source.setInputSource(fileSource);
// Now we need to create a StreamResult.
OutputStream out = new FileOutputStream(outputFile);
closeables.add(out);
StreamResult result = new StreamResult();
result.setOutputStream(out);
result.setSystemId(outputFile);
// Create a templates object for the identity transform. If you are going
// to transform a lot of documents, you should do this once and
// reuse the Templates object.
InputStream identityIn = new FileInputStream(identityFile);
closeables.add(identityIn);
StreamSource identitySource = new StreamSource();
identitySource.setSystemId(identityFile);
identitySource.setInputStream(identityIn);
TransformerFactory factory = TransformerFactory.newInstance();
Templates templates = factory.newTemplates(identitySource);
// Finally we need to create the transformer and do the transformation.
Transformer transformer = templates.newTransformer();
transformer.transform(source, result);
} finally {
// Some older XML processors are bad at cleaning up input and output streams,
// so we will do this manually.
for (Closeable closeable : closeables) {
if (closeable != null) {
try {
closeable.close();
} catch (Exception e) {
}
}
}
}