Commit 3fd59ad8 authored by Gerrit Hübbers's avatar Gerrit Hübbers 🃏
Browse files

WIP: Implement XmlXsltBundlesStreamSource

parent 173ad1d6
package org.gesis.dda.publishing.domain.impl;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Stream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.gesis.dda.publishing.domain.Bundle;
import org.gesis.dda.publishing.domain.BundlesStreamSource;
import org.gesis.dda.publishing.domain.Metadatum;
import org.gesis.dda.transformer.XmlBundles;
import org.gesis.dda.xslt.XsltUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.saxon.TransformerFactoryImpl;
public class XmlXsltBundlesStreamSource implements BundlesStreamSource {
private final static Logger LOG = LoggerFactory.getLogger(XmlXsltBundlesStreamSource.class);
private String reference = "xmlxslt-uuid-" + UUID.randomUUID().toString();
private String xmlPayload;
private String xslt;
public XmlXsltBundlesStreamSource(String xmlPayload, String xslt) {
this.xmlPayload = xmlPayload;
this.xslt = xslt;
}
public XmlXsltBundlesStreamSource(String xmlPayload, String xslt, long databaseId) {
this(xmlPayload, xslt);
this.reference = "xmlxslt-database-" + databaseId;
}
@Override
public Stream<Bundle> getBundlesStream() {
try {
//TransformerFactory factory = TransformerFactory.newInstance();
TransformerFactory factory = TransformerFactory.newInstance("org.apache.xalan.processor.TransformerFactoryImpl", TransformerFactoryImpl.class.getClassLoader() );
/*
net.sf.saxon.TransformerFactoryImpl factory = (TransformerFactoryImpl) TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", net.sf.saxon.TransformerFactoryImpl.class.getClassLoader() );
net.sf.saxon.Configuration saxonConfig = factory.getConfiguration();
Processor processor = (Processor) saxonConfig.getProcessor();
ExtensionFunction test = new Test();
processor.registerExtensionFunction(test);
ExtensionFunction callJava = new CallJavaExtensionFunction();
processor.registerExtensionFunction(callJava);
*/
Templates xslTemplate = factory.newTemplates( new StreamSource( new StringReader(xslt) ) );
Source xmlInput = new StreamSource( new StringReader(xmlPayload) );
StringWriter writer = new StringWriter();
Result xmlOutput = new StreamResult(writer);
Transformer transformer = xslTemplate.newTransformer();
transformer.setParameter("bundlesSourceReference", reference);
transformer.setParameter("util", new XsltUtil() );
transformer.transform(xmlInput, xmlOutput);
String xsltConvertedXmlOutput = writer.toString();
JAXBContext jaxbContext = JAXBContext.newInstance(XmlBundles.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
InputStream convertedXmlInputStream = new ByteArrayInputStream(xsltConvertedXmlOutput.getBytes(StandardCharsets.UTF_8) );
XmlBundles xmlBundles = (XmlBundles) unmarshaller.unmarshal(convertedXmlInputStream);
Stream<Bundle> bundlesStream = xmlBundles.getBundlesStream();
return bundlesStream;
}
catch (Throwable t) {
LOG.error("Problem with XmlXsltBundlesStreamSource.reference=" + reference, t);
throw new RuntimeException(t);
}
}
@Override
public String getReference() {
return reference;
}
@Override
public Set<Metadatum> getAllMetadata(String scopedIdentifier) {
// TODO Auto-generated method stub
return null;
}
}
package org.gesis.dda.xslt;
public class XsltUtil {
public static String hyphenizeIsbn(String input) {
String result;
// 978-3-8474-0969-4
result =
input.substring(0, 3) + "-" +
input.substring(3, 4) + "-" +
input.substring(4, 8) + "-" +
input.substring(8, 12) + "-" +
input.substring(12);
return result;
}
}
package org.gesis.dda.publishing.domain.impl;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.io.IOUtils;
import org.gesis.dda.publishing.domain.Bundle;
import org.gesis.dda.publishing.domain.Metadatum;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class XmlXsltBundlesStreamSourceTest {
private final static Logger LOG = LoggerFactory.getLogger(XmlXsltBundlesStreamSourceTest.class);
@Test
public void convertOnixXmlToBundlesXml() throws IOException, TransformerException {
String onixXmlString = IOUtils.toString(
getClass().
getClassLoader().
getResourceAsStream("xml/onix/onix-20180525.xml"), StandardCharsets.UTF_8);
LOG.info("onixXmlString={}", onixXmlString);
String xsltString = IOUtils.toString(
getClass().
getClassLoader().
getResourceAsStream("xslt/onix-budrich-2-xmlbundles.xslt"), StandardCharsets.UTF_8);
LOG.info("xsltString={}", xsltString);
// --- STEP 2: convert XML input according to XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Templates xslTemplate = factory.newTemplates( new StreamSource( new StringReader(xsltString) ) );
Source xmlInput = new StreamSource( new StringReader(onixXmlString) );
StringWriter writer = new StringWriter();
Result xmlOutput = new StreamResult(writer);
Transformer transformer = xslTemplate.newTransformer();
transformer.transform(xmlInput, xmlOutput);
String xsltConvertedXmlOutput = writer.toString();
LOG.info("---CONVERTED-----------------------");
LOG.info("{}", xsltConvertedXmlOutput);
/*
// STEP 3: convert XSLT-converted XML output to Java JAXB object
JAXBContext jaxbContext = JAXBContext.newInstance(XmlBundle.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
InputStream convertedXmlInputStream = new ByteArrayInputStream(xsltConvertedXmlOutput.getBytes(StandardCharsets.UTF_8) );
Bundle currentPartBundle = (Bundle) unmarshaller.unmarshal(convertedXmlInputStream);
bundleMetadata.addAll( currentPartBundle.getMetadata() );
// STEP 4: extract lastModifiedDate
StringReader sr = new StringReader(getRecordXmlDocumentResponseString);
//LOG.info("sr=\n{}", getRecordXmlDocumentResponseString);
JAXBContext oaiPmhjaxbContext = JAXBContext.newInstance(OAIPMHtype.class);
Unmarshaller oaiPmhUnmarshaller = oaiPmhjaxbContext.createUnmarshaller();
@SuppressWarnings("unchecked")
JAXBElement<OAIPMHtype> wrappedResponseObject = (JAXBElement<OAIPMHtype>) oaiPmhUnmarshaller.unmarshal(sr);
OAIPMHtype response = wrappedResponseObject.getValue();
lastModifiedString = response.getGetRecord().getRecord().getHeader().getDatestamp();
// STEP 5: add identifier metadatum
Metadatum reference = new SimpleMetadatum("internal.dda.reference", oaiPmhEndpoint + "@@" + oaiPmhIdentifier);
bundleMetadata.add(reference);
resultBundle = BundleBuilder.create().withMetadata(bundleMetadata).withLastModifiedString(lastModifiedString).build();
*/
}
@Test
public void exerciseBundlesStreamSource() throws IOException {
String onixXmlString = IOUtils.toString(
getClass().
getClassLoader().
getResourceAsStream("xml/onix/onix-20180525.xml"), StandardCharsets.UTF_8);
LOG.info("onixXmlString={}", onixXmlString);
String xsltString = IOUtils.toString(
getClass().
getClassLoader().
getResourceAsStream("xslt/onix-budrich-2-xmlbundles.xslt"), StandardCharsets.UTF_8);
LOG.info("xsltString={}", xsltString);
XmlXsltBundlesStreamSource underTest = new XmlXsltBundlesStreamSource(onixXmlString, xsltString, 4711);
Stream<Bundle> stream = underTest.getBundlesStream();
assertEquals(4, stream.count() );
assertEquals( "xmlxslt-database-4711", underTest.getReference() );
{
Bundle regierenBundle = underTest.getBundlesStream().filter(b -> b.getReference().equals("xmlxslt-database-4711@@f3ae7b1fec56419eaa3a34bed68232cb") ).findFirst().get();
LOG.info("regierenBundle=\n{}", regierenBundle);
Metadatum regierenBundleMetadatumInternalDdaReference = regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("internal.dda.reference")).findFirst().get();
assertEquals("xmlxslt-database-4711@@f3ae7b1fec56419eaa3a34bed68232cb", regierenBundleMetadatumInternalDdaReference.getValue() );
Stream<Metadatum> regierenBundleMetadataDcContributorAuthor = regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.contributor.author"));
assertEquals(1, regierenBundleMetadataDcContributorAuthor.count() );
assertEquals("Mai, Manfred", regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.contributor.author")).findFirst().get().getValue() );
Stream<Metadatum> regierenBundleMetadataDcContributorEditor = regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.contributor.editor"));
assertEquals(0, regierenBundleMetadataDcContributorEditor.count() );
Stream<Metadatum> regierenBundleMetadataDcDateIssued = regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.date.issued"));
assertEquals(1, regierenBundleMetadataDcDateIssued.count() );
assertEquals("2016", regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.date.issued")).findFirst().get().getValue() );
Stream<Metadatum> regierenBundleMetadataDcIdentifierIsbn = regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.identifier.isbn"));
assertEquals(1, regierenBundleMetadataDcIdentifierIsbn.count() );
assertEquals("978-3-8474-0969-4", regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.identifier.isbn")).findFirst().get().getValue() );
Stream<Metadatum> regierenBundleMetadataDcLanguage = regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.language"));
assertEquals(1, regierenBundleMetadataDcLanguage.count() );
assertEquals("de", regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.language")).findFirst().get().getValue() );
assertEquals(1, regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.publisher")).count() );
assertEquals("Verlag Barbara Budrich", regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.publisher")).findFirst().get().getValue() );
assertEquals(1, regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.title")).count() );
assertEquals("Regieren in der modernen Gesellschaft: Governance aus der Sicht der Ministerialbürokratie", regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.title")).findFirst().get().getValue() );
assertEquals(1, regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.publisher.country")).count() );
assertEquals("DEU", regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.publisher.country")).findFirst().get().getValue() );
assertEquals(1, regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.publisher.city")).count() );
assertEquals("Opladen", regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.publisher.city")).findFirst().get().getValue() );
assertEquals(1, regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.identifier.doi")).count() );
assertEquals("https://doi.org/10.3224/84740518", regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.identifier.doi")).findFirst().get().getValue() );
assertEquals(1, regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.source.pageinfo")).count() );
assertEquals("233", regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.source.pageinfo")).findFirst().get().getValue() );
Set<Metadatum> dcSubjectOtherMetadata = regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.subject.other")).collect( Collectors.toSet() );
assertEquals(8, dcSubjectOtherMetadata.size() );
assertEquals(1, dcSubjectOtherMetadata.stream().filter( m -> "Nonbooks, PBS / Politikwissenschaft".equals( m.getValue() ) ).count() );
assertEquals(1, dcSubjectOtherMetadata.stream().filter( m -> "Politikwissenschaft".equals( m.getValue() ) ).count() );
assertEquals(1, dcSubjectOtherMetadata.stream().filter( m -> "Ministerialbürokratie".equals( m.getValue() ) ).count() );
assertEquals(1, dcSubjectOtherMetadata.stream().filter( m -> "Governance".equals( m.getValue() ) ).count() );
assertEquals(1, dcSubjectOtherMetadata.stream().filter( m -> "Verwaltung".equals( m.getValue() ) ).count() );
assertEquals(1, dcSubjectOtherMetadata.stream().filter( m -> "Policyforschung".equals( m.getValue() ) ).count() );
assertEquals(1, dcSubjectOtherMetadata.stream().filter( m -> "Öffentliche Verwaltung".equals( m.getValue() ) ).count() );
assertEquals(1, dcSubjectOtherMetadata.stream().filter( m -> "Kommunal-, Regional- Landes und Lokalregierung".equals( m.getValue() ) ).count() );
assertEquals(1, regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.description.abstract")).count() );
assertEquals("Wie lässt sich das Handeln der Regierung in modernen Gesellschaften theoretisch fassen? Schon die Autoren der amerikanischen Verfassung haben die Notwendigkeit erkannt, die Exekutivgewalt einzuhegen und sie mit der Legislative zu verschränken. Dieses Prinzip gilt bis heute, doch in modernen Gesellschaften kommt hinzu, dass die Zivilgesellschaft und ihre Medien mit Regierung und Verwaltung auf vielfältige Weise miteinander verbunden sind. Die Frage ist, wie der moderne Staat als wichtigster Akteur der Politik mit der Regierung als seinem stärksten Instrument legitime Ziele erreichen kann. Der Autor zeigt die Interdependenzen zwischen Regierung, Zivilgesellschaft, Verbänden und Parlament auf und demonstriert anhand verschiedener Beispiele, dass die Exekutive kein abgehobenes Eigenleben führt. Ein zentrales Kapitel ist die Beschreibung des Innenlebens der Ministerialbürokratie. Gerade der Einblick in die täglichen Routinen im Umgang mit der Komplexität einzelner Inputs ist aufschlussreich für die Frage nach den Möglichkeiten und Grenzen politischer Gestaltung.", regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.description.abstract")).findFirst().get().getValue() );
assertEquals(0, regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.source.series")).count() );
assertEquals(0, regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.source.edition")).count() );
assertEquals(1, regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.type.stock")).count() );
assertEquals("article", regierenBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.type.stock")).findFirst().get().getValue() );
}
{
Bundle bildungsforschungBundle = underTest.getBundlesStream().filter(b -> b.getReference().equals("xmlxslt-database-4711@@e8d053068a59466486680c6c90ee459b") ).findFirst().get();
LOG.info("regierenBundle=\n{}", bildungsforschungBundle);
assertEquals(1, bildungsforschungBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.title")).count() );
assertEquals("Theorien in der qualitativen Bildungsforschung – Qualitative Bildungsforschung als Theoriegenerierung", bildungsforschungBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.title")).findFirst().get().getValue() );
assertEquals(1, bildungsforschungBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.source.series")).count() );
assertEquals("Schriftenreihe der DGfE-Kommission Qualitative Bildungs- und Biographieforschung", bildungsforschungBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.source.series")).findFirst().get().getValue() );
assertEquals(0, bildungsforschungBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.source.edition")).count() );
assertEquals(1, bildungsforschungBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.type.stock")).count() );
assertEquals("collection", bildungsforschungBundle.getMetadata().stream().filter(m -> m.getKey().equals("dc.type.stock")).findFirst().get().getValue() );
}
}
}
package org.gesis.dda.transformer;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.gesis.dda.publishing.domain.Bundle;
import org.gesis.dda.publishing.domain.BundlesStreamSource;
import org.gesis.dda.publishing.domain.Metadatum;
import org.gesis.dda.publishing.domain.impl.XmlBundle;
@XmlRootElement(name = "bundles")
public class XmlBundles {
public class XmlBundles implements BundlesStreamSource {
@XmlElement(name = "reference")
private String reference;
@XmlElement(name="bundle")
Set<XmlBundle> bundles;
@Override
public String getReference() {
return reference;
}
public Set<XmlBundle> getBundles() {
return bundles;
}
@Override
public Stream<Bundle> getBundlesStream() {
Set<Bundle> view = new HashSet<>(bundles);
return view.stream();
}
@Override
public Set<Metadatum> getAllMetadata(String scopedIdentifier) {
// TODO Auto-generated method stub
return null;
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ONIXmessage release="2.1"><header><m174>VLB - Verzeichnis Lieferbarer Bücher</m174><m175>MVB Marketing- und Verlagsservice des Buchhandels GmbH, 069.1306.550</m175><m283>serviceline@mvb-online.de</m283><m182>20180523</m182></header>
<product datestamp="20180522">
<a001>f3ae7b1fec56419eaa3a34bed68232cb</a001>
<a002>03</a002>
<productidentifier>
<b221>02</b221>
<b244>3847409697</b244>
</productidentifier>
<productidentifier>
<b221>03</b221>
<b244>9783847409694</b244>
</productidentifier>
<productidentifier>
<b221>06</b221>
<b244>10.3224/84740518</b244>
</productidentifier>
<productidentifier>
<b221>15</b221>
<b244>9783847409694</b244>
</productidentifier>
<b012>DG</b012>
<b385>10</b385>
<b211>002</b211>
<b277>00</b277>
<title>
<b202>01</b202>
<b203>Regieren in der modernen Gesellschaft</b203>
<b029>Governance aus der Sicht der Ministerialbürokratie</b029>
</title>
<contributor>
<b034>1</b034>
<b035>A01</b035>
<b340>1</b340>
<b036>Manfred Mai</b036>
<b037>Mai, Manfred</b037>
<b039>Manfred</b039>
<b040>Mai</b040>
</contributor>
<b057>1</b057>
<language>
<b253>01</b253>
<b252>ger</b252>
</language>
<b255>233</b255>
<extent>
<b218>00</b218>
<b219>233</b219>
<b220>03</b220>
</extent>
<mainsubject>
<b191>26</b191>
<b068>2.0</b068>
<b069>9730</b069>
<b070>Nonbooks, PBS / Politikwissenschaft</b070>
</mainsubject>
<mainsubject sourcename="Publisher">
<b191>93</b191>
<b068>1.2</b068>
<b069>JPA</b069>
<b070>Politikwissenschaft</b070>
</mainsubject>
<subject>
<b067>20</b067>
<b070>Ministerialbürokratie</b070>
</subject>
<subject>
<b067>20</b067>
<b070>Governance</b070>
</subject>
<subject>
<b067>20</b067>
<b070>Verwaltung</b070>
</subject>
<subject>
<b067>20</b067>
<b070>Policyforschung</b070>
</subject>
<subject sourcename="Publisher">
<b067>93</b067>
<b068>1.2</b068>
<b069>JPP</b069>
<b070>Öffentliche Verwaltung</b070>
</subject>
<subject sourcename="Publisher">
<b067>93</b067>
<b068>1.2</b068>
<b069>JPR</b069>
<b070>Kommunal-, Regional- Landes und Lokalregierung</b070>
</subject>
<othertext>
<d102>01</d102>
<d103>06</d103>
<d104>Wie lässt sich das Handeln der Regierung in modernen Gesellschaften theoretisch fassen? Schon die Autoren der amerikanischen Verfassung haben die Notwendigkeit erkannt, die Exekutivgewalt einzuhegen und sie mit der Legislative zu verschränken. Dieses Prinzip gilt bis heute, doch in modernen Gesellschaften kommt hinzu, dass die Zivilgesellschaft und ihre Medien mit Regierung und Verwaltung auf vielfältige Weise miteinander verbunden sind. Die Frage ist, wie der moderne Staat als wichtigster Akteur der Politik mit der Regierung als seinem stärksten Instrument legitime Ziele erreichen kann. Der Autor zeigt die Interdependenzen zwischen Regierung, Zivilgesellschaft, Verbänden und Parlament auf und demonstriert anhand verschiedener Beispiele, dass die Exekutive kein abgehobenes Eigenleben führt. Ein zentrales Kapitel ist die Beschreibung des Innenlebens der Ministerialbürokratie. Gerade der Einblick in die täglichen Routinen im Umgang mit der Komplexität einzelner Inputs ist aufschlussreich für die Frage nach den Möglichkeiten und Grenzen politischer Gestaltung.</d104>
</othertext>
<othertext>
<d102>13</d102>
<d103>06</d103>
<d104>Dr. Manfred Mai, außerplanmäßiger Professor für Politikwissenschaft, Universität Duisburg-Essen und Hochschule Düsseldorf</d104>
</othertext>
<othertext>
<d102>99</d102>
<d104>DE</d104>
</othertext>
<mediafile>
<f114>04</f114>
<f115>03</f115>
<f116>01</f116>
<f117>https://api.vlb.de/api/v1/cover/9783847409694/m</f117>
</mediafile>
<publisher>
<b291>01</b291>
<b241>05</b241>
<b243>5195102</b243>
<b081>Verlag Barbara Budrich</b081>
</publisher>
<b209>Leverkusen-Opladen</b209>
<b083>DE</b083>
<b394>04</b394>
<b003>20160523</b003>
<salesrights>
<b089>01</b089>
<b388>WORLD</b388>
</salesrights>
<relatedproduct>
<h208>13</h208>
<productidentifier>
<b221>15</b221>
<b244>9783847405184</b244>
</productidentifier>
<b012>BC</b012>
</relatedproduct>
<supplydetail>
<supplieridentifier>
<j345>05</j345>
<b244>5195102</b244>
</supplieridentifier>
<j137>Verlag Barbara Budrich</j137>
<j292>01</j292>
<j141>IP</j141>
<j396>20</j396>
<j192>01</j192>
</supplydetail>
</product>
<product datestamp="20180522">
<a001>e8d053068a59466486680c6c90ee459b</a001>
<a002>03</a002>
<productidentifier>
<b221>02</b221>
<b244>384740900X</b244>
</productidentifier>
<productidentifier>
<b221>03</b221>
<b244>9783847409007</b244>
</productidentifier>
<productidentifier>
<b221>06</b221>
<b244>10.3224/84740778</b244>
</productidentifier>
<productidentifier>
<b221>15</b221>
<b244>9783847409007</b244>
</productidentifier>
<b012>DG</b012>
<b385>10</b385>
<b211>002</b211>
<b277>00</b277>
<series>
<seriesidentifier>
<b273>04</b273>
<b244>AAXOS28</b244>
</seriesidentifier>
<b018>Schriftenreihe der DGfE-Kommission Qualitative Bildungs- und Biographieforschung</b018>
<title>
<b202>01</b202>
<b203>Schriftenreihe der DGfE-Kommission Qualitative Bildungs- und Biographieforschung</b203>
</title>
<b019>1</b019>
</series>
<title>
<b202>01</b202>
<b203>Theorien in der qualitativen Bildungsforschung – Qualitative Bildungsforschung als Theoriegenerierung</b203>
</title>
<contributor>
<b034>1</b034>
<b035>B01</b035>
<b340>1</b340>
<b036>Robert Kreitz</b036>
<b037>Kreitz, Robert</b037>
<b039>Robert</b039>
<b040>Kreitz</b040>
</contributor>
<contributor>
<b034>2</b034>