/*
* Copyright (C) 2012 Jan Pokorsky
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cz.cas.lib.proarc.common.xml;
import cz.cas.lib.proarc.common.export.mets.ValidationErrorHandler;
import cz.cas.lib.proarc.common.mods.ModsUtils;
import cz.cas.lib.proarc.common.mods.custom.ModsConstants;
import cz.cas.lib.proarc.common.mods.custom.PageMapperTest;
import cz.cas.lib.proarc.mods.ModsDefinition;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Validator;
import org.custommonkey.xmlunit.SimpleNamespaceContext;
import org.custommonkey.xmlunit.XMLAssert;
import org.custommonkey.xmlunit.XMLUnit;
import org.junit.After;
import org.junit.AfterClass;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.xml.sax.InputSource;
/**
*
* @author Jan Pokorsky
*/
public class TransformersTest {
private static final Logger LOG = Logger.getLogger(TransformersTest.class.getName());
private static ProxySelector defaultProxy;
private static List<URI> externalConnections;
public TransformersTest() {
}
@BeforeClass
public static void setUpClass() throws Exception {
defaultProxy = ProxySelector.getDefault();
// detect external connections
ProxySelector.setDefault(new ProxySelector() {
@Override
public List<Proxy> select(URI uri) {
externalConnections.add(uri);
return defaultProxy.select(uri);
}
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
defaultProxy.connectFailed(uri, sa, ioe);
}
});
}
@AfterClass
public static void tearDownClass() throws Exception {
}
@Before
public void setUp() {
externalConnections = new ArrayList<URI>();
XMLUnit.setIgnoreWhitespace(true);
}
@After
public void tearDown() {
assertTrue(externalConnections.toString(), externalConnections.isEmpty());
XMLUnit.setIgnoreWhitespace(false);
XMLUnit.setNormalizeWhitespace(false);
}
@Test
public void testMarcAsMods() throws Exception {
XMLUnit.setNormalizeWhitespace(true);
InputStream goldenIS = TransformersTest.class.getResourceAsStream("alephXServerDetailResponseAsMods.xml");
assertNotNull(goldenIS);
InputStream xmlIS = TransformersTest.class.getResourceAsStream("alephXServerDetailResponseAsMarcXml.xml");// from test
assertNotNull(xmlIS);
StreamSource streamSource = new StreamSource(xmlIS);
Transformers mt = new Transformers();
try {
byte[] contents = mt.transformAsBytes(streamSource, Transformers.Format.MarcxmlAsMods3);
assertNotNull(contents);
// System.out.println(new String(contents, "UTF-8"));
XMLAssert.assertXMLEqual(new InputSource(goldenIS), new InputSource(new ByteArrayInputStream(contents)));
} finally {
close(xmlIS);
close(goldenIS);
}
}
/**
* Tests mapping of 910a(sigla) as {@code <physicalLocation>} and 910b(signatura) as {@code <shelfLocator>}.
*/
@Test
public void testMarcAsMods_Issue32() throws Exception {
InputStream xmlIS = TransformersTest.class.getResourceAsStream("marc.xml");
assertNotNull(xmlIS);
StreamSource streamSource = new StreamSource(xmlIS);
Transformers mt = new Transformers();
try {
byte[] contents = mt.transformAsBytes(streamSource, Transformers.Format.MarcxmlAsMods3);
assertNotNull(contents);
String xmlResult = new String(contents, "UTF-8");
// System.out.println(xmlResult);
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(new HashMap() {{
put("m", ModsConstants.NS);
}}));
XMLAssert.assertXpathEvaluatesTo("HKA001", "/m:mods/m:location/m:physicalLocation[1]", xmlResult);
XMLAssert.assertXpathEvaluatesTo("test sigla", "/m:mods/m:location/m:physicalLocation[2]", xmlResult);
XMLAssert.assertXpathEvaluatesTo("2", "count(/m:mods/m:location/m:physicalLocation)", xmlResult);
XMLAssert.assertXpathEvaluatesTo("54 487", "/m:mods/m:location/m:shelfLocator[1]", xmlResult);
XMLAssert.assertXpathEvaluatesTo("test signatura", "/m:mods/m:location/m:shelfLocator[2]", xmlResult);
XMLAssert.assertXpathEvaluatesTo("2", "count(/m:mods/m:location/m:shelfLocator)", xmlResult);
validateMods(new StreamSource(new ByteArrayInputStream(contents)));
} finally {
close(xmlIS);
}
}
/**
* Tests mapping of fields 310a and 008/18 to {@code frequency@authority}.
* See issue 118 and 181.
*/
@Test
public void testMarcAsMods_FrequencyAuthority_Issue181() throws Exception {
InputStream xmlIS = TransformersTest.class.getResourceAsStream("frequencyAuthority.xml");
assertNotNull(xmlIS);
StreamSource streamSource = new StreamSource(xmlIS);
Transformers mt = new Transformers();
try {
byte[] contents = mt.transformAsBytes(streamSource, Transformers.Format.MarcxmlAsMods3);
assertNotNull(contents);
String xmlResult = new String(contents, "UTF-8");
// System.out.println(xmlResult);
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(new HashMap() {{
put("m", ModsConstants.NS);
}}));
XMLAssert.assertXpathNotExists("/m:mods/m:originInfo/m:frequency[1]/@authority", xmlResult);
XMLAssert.assertXpathEvaluatesTo("2x ročně", "/m:mods/m:originInfo/m:frequency[1]", xmlResult);
XMLAssert.assertXpathEvaluatesTo("marcfrequency", "/m:mods/m:originInfo/m:frequency[2]/@authority", xmlResult);
XMLAssert.assertXpathEvaluatesTo("Semiannual", "/m:mods/m:originInfo/m:frequency[2]", xmlResult);
validateMods(new StreamSource(new ByteArrayInputStream(contents)));
} finally {
close(xmlIS);
}
}
/**
* Tests mapping of fields 600, 610, 611, 630, 648, 650, 651 indicator_9 $2 to {@code subject@authority}.
* See issue 182.
*/
@Test
public void testMarcAsMods_SubjectAuthority_Issue182() throws Exception {
InputStream xmlIS = TransformersTest.class.getResourceAsStream("marc_subject_65X_X9.xml");
assertNotNull(xmlIS);
StreamSource streamSource = new StreamSource(xmlIS);
Transformers mt = new Transformers();
try {
byte[] contents = mt.transformAsBytes(streamSource, Transformers.Format.MarcxmlAsMods3);
assertNotNull(contents);
String xmlResult = new String(contents, "UTF-8");
// System.out.println(xmlResult);
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(new HashMap() {{
put("m", ModsConstants.NS);
}}));
// 600
XMLAssert.assertXpathExists("/m:mods/m:subject[@authority='czenas']/m:name[@type='personal']/m:namePart[text()='Novák, A. Jiří']", xmlResult);
// 650
XMLAssert.assertXpathExists("/m:mods/m:subject[@authority='czenas']/m:topic[text()='daňové delikty']", xmlResult);
XMLAssert.assertXpathExists("/m:mods/m:subject[@authority='eczenas']/m:topic[text()='tax delinquency']", xmlResult);
// 651
XMLAssert.assertXpathExists("/m:mods/m:subject[@authority='czenas']/m:geographic[text()='Česko']", xmlResult);
XMLAssert.assertXpathExists("/m:mods/m:subject[@authority='eczenas']/m:geographic[text()='Czechia']", xmlResult);
validateMods(new StreamSource(new ByteArrayInputStream(contents)));
} finally {
close(xmlIS);
}
}
/**
* Tests mapping of field 653 indicator_9 $a to {@code subject/topic@lang}.
* See issue 185.
* See issue 433.
*/
@Test
public void testMarcAsMods_SubjectTopic_Issue185_Issue433() throws Exception {
InputStream xmlIS = TransformersTest.class.getResourceAsStream("marc_subject_65X_X9.xml");
assertNotNull(xmlIS);
StreamSource streamSource = new StreamSource(xmlIS);
Transformers mt = new Transformers();
try {
byte[] contents = mt.transformAsBytes(streamSource, Transformers.Format.MarcxmlAsMods3);
assertNotNull(contents);
String xmlResult = new String(contents, "UTF-8");
// System.out.println(xmlResult);
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(new HashMap() {{
put("m", ModsConstants.NS);
}}));
// 653
XMLAssert.assertXpathExists("/m:mods/m:subject[not(@authority)]/m:topic[text()='kočky' and @lang='cze']", xmlResult);
XMLAssert.assertXpathExists("/m:mods/m:subject[not(@authority)]/m:topic[text()='cats' and @lang='eng']", xmlResult);
XMLAssert.assertXpathNotExists("/m:mods/m:subject/m:name/m:namePart[text()='kočky']", xmlResult);
XMLAssert.assertXpathNotExists("/m:mods/m:subject/m:name/m:namePart[text()='cats']", xmlResult);
validateMods(new StreamSource(new ByteArrayInputStream(contents)));
} finally {
close(xmlIS);
}
}
/**
* Test mapping of 072#7 $x to {@code subject/topic} and $a/$9 to {@code classification}.
* See issue 303.
*/
@Test
public void testMarcAsMods_Conspectus_Issue303() throws Exception {
InputStream xmlIS = TransformersTest.class.getResourceAsStream("marc.xml");
assertNotNull(xmlIS);
StreamSource streamSource = new StreamSource(xmlIS);
Transformers mt = new Transformers();
try {
byte[] contents = mt.transformAsBytes(streamSource, Transformers.Format.MarcxmlAsMods3);
assertNotNull(contents);
String xmlResult = new String(contents, "UTF-8");
// System.out.println(xmlResult);
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(new HashMap() {{
put("m", ModsConstants.NS);
}}));
XMLAssert.assertXpathEvaluatesTo("Umění", "/m:mods/m:subject[@authority='Konspekt']/m:topic", xmlResult);
XMLAssert.assertXpathEvaluatesTo("7.01/.09", "/m:mods/m:classification[@authority='udc' and @edition='Konspekt']", xmlResult);
XMLAssert.assertXpathEvaluatesTo("21", "/m:mods/m:classification[@authority='Konspekt']", xmlResult);
validateMods(new StreamSource(new ByteArrayInputStream(contents)));
} finally {
close(xmlIS);
}
}
/**
* Tests mapping of field 100,700 $7 to {@code name@authorityURI} and {@code name@valueURI}.
* See issue 305.
*/
@Test
public void testMarcAsMods_AuthorityId_Issue305() throws Exception {
InputStream xmlIS = TransformersTest.class.getResourceAsStream("marc_subject_65X_X9.xml");
assertNotNull(xmlIS);
StreamSource streamSource = new StreamSource(xmlIS);
Transformers mt = new Transformers();
try {
byte[] contents = mt.transformAsBytes(streamSource, Transformers.Format.MarcxmlAsMods3);
assertNotNull(contents);
String xmlResult = new String(contents, "UTF-8");
// System.out.println(xmlResult);
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(new HashMap() {{
put("m", ModsConstants.NS);
}}));
// test 100 1# $a Kocina, Jan, $d 1960- $4 aut $7 xx0113245
XMLAssert.assertXpathExists("/m:mods/m:name[@type='personal'"
+ " and @authorityURI='http://aut.nkp.cz'"
+ " and @valueURI='http://aut.nkp.cz/xx0113245']"
+ "/m:namePart[text()='Kocina, Jan']"
+ "/../m:namePart[@type='date' and text()='1960-']"
+ "/../m:role/m:roleTerm[text()='aut']", xmlResult);
// test 700 1# $a Honzík, Bohumil, $d 1972- $4 aut $7 jn20020422016
XMLAssert.assertXpathExists("/m:mods/m:name[@type='personal'"
+ " and @authorityURI='http://aut.nkp.cz'"
+ " and @valueURI='http://aut.nkp.cz/jn20020422016']"
+ "/m:namePart[text()='Honzík, Bohumil']"
+ "/../m:namePart[@type='date' and text()='1972-']"
+ "/../m:role/m:roleTerm[text()='aut']", xmlResult);
// test 700 1# $a Test Without AuthorityId $d 1972- $4 aut
XMLAssert.assertXpathExists("/m:mods/m:name[@type='personal'"
+ " and not(@authorityURI)"
+ " and not(@valueURI)]"
+ "/m:namePart[text()='Test Without AuthorityId']"
+ "/../m:namePart[@type='date' and text()='1972-']"
+ "/../m:role/m:roleTerm[text()='aut']", xmlResult);
validateMods(new StreamSource(new ByteArrayInputStream(contents)));
} finally {
close(xmlIS);
}
}
/**
* Tests mapping of field 510 $c to {@code part/detail/number}.
* See issue 306.
*/
@Test
public void testMarcAsMods_RelatedItemPartDetailNumber_Issue306() throws Exception {
InputStream xmlIS = TransformersTest.class.getResourceAsStream("marc_subject_65X_X9.xml");
assertNotNull(xmlIS);
StreamSource streamSource = new StreamSource(xmlIS);
Transformers mt = new Transformers();
try {
byte[] contents = mt.transformAsBytes(streamSource, Transformers.Format.MarcxmlAsMods3);
assertNotNull(contents);
String xmlResult = new String(contents, "UTF-8");
// System.out.println(xmlResult);
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(new HashMap() {{
put("m", ModsConstants.NS);
}}));
// test 510 4# $a Knihopis 1 $c K01416
XMLAssert.assertXpathExists("/m:mods/m:relatedItem[@type='isReferencedBy']"
+ "/m:titleInfo/m:title[text()='Knihopis 1']", xmlResult);
XMLAssert.assertXpathEvaluatesTo("K01416", "/m:mods/m:relatedItem[@type='isReferencedBy']"
+ "/m:titleInfo/m:title[text()='Knihopis 1']/../../m:part/m:detail[@type='part']/m:number", xmlResult);
// test 510 0# $a Knihopis 2
XMLAssert.assertXpathExists("/m:mods/m:relatedItem[@type='isReferencedBy']"
+ "/m:titleInfo/m:title[text()='Knihopis 2']", xmlResult);
XMLAssert.assertXpathNotExists("/m:mods/m:relatedItem[@type='isReferencedBy']"
+ "/m:titleInfo/m:title[text()='Knihopis 2']/../../m:part", xmlResult);
validateMods(new StreamSource(new ByteArrayInputStream(contents)));
} finally {
close(xmlIS);
}
}
/**
* Tests mapping of field 787 to {@code relatedItem}.
* See issue 313.
*/
@Test
public void testMarcAsMods_RelatedItem_Issue313() throws Exception {
InputStream xmlIS = TransformersTest.class.getResourceAsStream("marc_relatedItem_787.xml");
assertNotNull(xmlIS);
StreamSource streamSource = new StreamSource(xmlIS);
Transformers mt = new Transformers();
try {
byte[] contents = mt.transformAsBytes(streamSource, Transformers.Format.MarcxmlAsMods3);
assertNotNull(contents);
String xmlResult = new String(contents, "UTF-8");
// System.out.println(xmlResult);
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(new HashMap() {{
put("m", ModsConstants.NS);
}}));
// test 78708 |i Recenze na: |a Čeřovský, Jan |t Jak jsme zachraňovali svět aneb Půl století ve službách ochrany přírody |d Praha : Nakladatelství Academia, 2014 |4 kniha
XMLAssert.assertXpathEvaluatesTo(
"Jak jsme zachraňovali svět aneb Půl století ve službách ochrany přírody",
"/m:mods/m:relatedItem[not(@type) and @displayLabel='Recenze na:']"
+ "/m:titleInfo/m:title/text()", xmlResult);
XMLAssert.assertXpathEvaluatesTo(
"Čeřovský, Jan",
"/m:mods/m:relatedItem[not(@type) and @displayLabel='Recenze na:']"
+ "/m:name/m:namePart/text()", xmlResult);
XMLAssert.assertXpathEvaluatesTo(
"Praha : Nakladatelství Academia, 2014",
"/m:mods/m:relatedItem[not(@type) and @displayLabel='Recenze na:']"
+ "/m:originInfo/m:publisher/text()", xmlResult);
validateMods(new StreamSource(new ByteArrayInputStream(contents)));
} finally {
close(xmlIS);
}
}
/**
* Tests mapping of field 520 and subfield $9 to {@code abstract@lang}.
* See issue 434.
*/
@Test
public void testMarcAsMods_AbstractLang_Issue434() throws Exception {
InputStream xmlIS = TransformersTest.class.getResourceAsStream("marc_subject_65X_X9.xml");
assertNotNull(xmlIS);
StreamSource streamSource = new StreamSource(xmlIS);
Transformers mt = new Transformers();
try {
byte[] contents = mt.transformAsBytes(streamSource, Transformers.Format.MarcxmlAsMods3);
assertNotNull(contents);
String xmlResult = new String(contents, "UTF-8");
// System.out.println(xmlResult);
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(new HashMap() {{
put("m", ModsConstants.NS);
}}));
XMLAssert.assertXpathExists("/m:mods/m:abstract[@lang='cze' and @type='Abstract' and text()='Text cze']", xmlResult);
XMLAssert.assertXpathExists("/m:mods/m:abstract[@lang='eng' and @type='Abstract' and text()='Text eng']", xmlResult);
XMLAssert.assertXpathExists("/m:mods/m:abstract[not(@lang) and @type='Abstract' and text()='Text no lang']", xmlResult);
validateMods(new StreamSource(new ByteArrayInputStream(contents)));
} finally {
close(xmlIS);
}
}
@Test
public void testOaiMarcAsMarc() throws Exception {
InputStream goldenIS = TransformersTest.class.getResourceAsStream("alephXServerDetailResponseAsMarcXml.xml");
assertNotNull(goldenIS);
InputStream xmlIS = TransformersTest.class.getResourceAsStream("alephXServerDetailResponseAsOaiMarc.xml");
assertNotNull(xmlIS);
StreamSource streamSource = new StreamSource(xmlIS);
Transformers mt = new Transformers();
try {
byte[] contents = mt.transformAsBytes(streamSource, Transformers.Format.OaimarcAsMarc21slim);
assertNotNull(contents);
// System.out.println(new String(contents, "UTF-8"));
XMLAssert.assertXMLEqual(new InputSource(goldenIS), new InputSource(new ByteArrayInputStream(contents)));
} finally {
close(xmlIS);
close(goldenIS);
}
}
@Test
public void testAlephXServerDetailNamespaceFix() throws Exception {
InputStream goldenIS = TransformersTest.class.getResourceAsStream("alephXServerDetailResponseFixed.xml");
assertNotNull(goldenIS);
InputStream xmlIS = TransformersTest.class.getResourceAsStream("../catalog/alephXServerDetailResponse.xml");
assertNotNull(xmlIS);
StreamSource streamSource = new StreamSource(xmlIS);
Transformers mt = new Transformers();
try {
byte[] contents = mt.transformAsBytes(streamSource, Transformers.Format.AlephOaiMarcFix);
assertNotNull(contents);
// System.out.println(new String(contents, "UTF-8"));
XMLAssert.assertXMLEqual(new InputSource(goldenIS), new InputSource(new ByteArrayInputStream(contents)));
} finally {
close(xmlIS);
close(goldenIS);
}
}
@Test
public void testModsAsHtml() throws Exception {
// XMLUnit.setNormalizeWhitespace(true);
// InputStream goldenIS = TransformersTest.class.getResourceAsStream("alephXServerDetailResponseAsMods.xml");
// assertNotNull(goldenIS);
InputStream xmlIS = TransformersTest.class.getResourceAsStream("alephXServerDetailResponseAsMods.xml");
assertNotNull(xmlIS);
StreamSource streamSource = new StreamSource(xmlIS);
Transformers mt = new Transformers();
Map<String, Object> params = ModsUtils.modsAsHtmlParameters(Locale.ENGLISH);
try {
byte[] contents = mt.transformAsBytes(streamSource, Transformers.Format.ModsAsHtml, params);
assertNotNull(contents);
// System.out.println(new String(contents, "UTF-8"));
// XMLAssert.assertXMLEqual(new InputSource(goldenIS), new InputSource(new ByteArrayInputStream(contents)));
} finally {
close(xmlIS);
// close(goldenIS);
}
}
@Test
public void testModsAsFedoraLabel_Page() throws Exception {
assertEquals("[1], Blank",
modsAsFedoraLabel(PageMapperTest.class.getResourceAsStream("page_mods.xml"), "model:page"));
}
@Test
public void testModsAsFedoraLabel_Issue() throws Exception {
assertEquals("1",
modsAsFedoraLabel(PageMapperTest.class.getResourceAsStream("issue_mods.xml"), "model:periodicalitem"));
}
@Test
public void testModsAsFedoraLabel_Volume() throws Exception {
assertEquals("1893, 1",
modsAsFedoraLabel(PageMapperTest.class.getResourceAsStream("volume_mods.xml"), "model:periodicalvolume"));
}
/** Tests label with date but missing volume number. */
@Test
public void testModsAsFedoraLabel_Volume_issue222() throws Exception {
assertEquals("1893",
modsAsFedoraLabel(PageMapperTest.class.getResourceAsStream("volume_mods_issue222.xml"), "model:periodicalvolume"));
}
@Test
public void testModsAsFedoraLabel_Periodical() throws Exception {
assertEquals("MTITLE[0]: STITLE[0]",
modsAsFedoraLabel(PageMapperTest.class.getResourceAsStream("periodical_mods.xml"), "model:periodical"));
}
@Test
public void testModsAsFedoraLabel_Empty() throws Exception {
String label = ModsUtils.getLabel(new ModsDefinition(), "model:page");
assertEquals("?", label);
}
private String modsAsFedoraLabel(InputStream xmlIS, String model) throws Exception {
assertNotNull(xmlIS);
StreamSource streamSource = new StreamSource(xmlIS);
Transformers mt = new Transformers();
Map<String, Object> params = new HashMap<String, Object>();
params.put("MODEL", model);
try {
byte[] contents = mt.transformAsBytes(streamSource, Transformers.Format.ModsAsFedoraLabel, params);
assertNotNull(contents);
String label = new String(contents, "UTF-8");
// System.out.println(label);
return label;
} finally {
close(xmlIS);
}
}
private void validateMods(Source source) throws Exception {
Validator v = ModsUtils.getSchema().newValidator();
ValidationErrorHandler handler = new ValidationErrorHandler();
v.setErrorHandler(handler);
v.validate(source);
List<String> errors = handler.getValidationErrors();
assertTrue(errors.toString(), errors.isEmpty());
}
private static void close(InputStream is) {
if (is != null) {
try {
is.close();
} catch (IOException ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
}
}