multiple xml files from directory to character strings in R - r

I have seen several similar questions, but none that addressed specifically my problem:
given a novel in xml file (this is a very small cut from the start and the end)
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="https://github.com/COST-ELTEC/Schemas/raw/master/eltec-0.rng" type="application/xml"schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="https://github.com/COST-ELTEC/Schemas/raw/master/eltec-0.rng" type="application/xml"schematypens="http://purl.oclc.org/dsdl/schematron"?>
<TEI xmlns="http://www.tei-c.org/ns/1.0" xml:id="CHE-DEU011" xml:lang="de">
<teiHeader>
<fileDesc>
<titleStmt>
<title>Pilatus. Eine Erzählung aus den Bergen: ELTeC ausgabe</title>
<author ref="https://en.wikipedia.org/wiki/Heinrich_Federer">Federer, Heinrich (1866-1928)</author>
<respStmt>
<resp>ELTeC conversion</resp>
<name>Priska Rüegg</name>
</respStmt>
</titleStmt>
<extent>
<measure unit="pages">360</measure>
<measure unit="words">79740</measure>
</extent>
<publicationStmt>
<publisher ref="https://distant-reading.net">COST Action "Distant Reading for European Literary History" (CA16204)
</publisher>
<distributor ref="https://zenodo.org/communities/eltec/">Zenodo.org</distributor>
<date when="2020"/>
<availability>
<licence target="https://creativecommons.org/licenses/by/4.0/"/>
</availability>
</publicationStmt>
<sourceDesc>
<bibl type="digitalSource">
<ref target="https://archive.org/details/pilatuseineerz00fedeuoft/page/n3/mode/2up"/>
<respStmt><resp>Scan</resp>
<name>archive</name></respStmt></bibl>
<bibl type="firstEdition">
<title>Pilatus. Eine Erzählung aus den Bergen</title>
<author>Federer, Heinrich</author>
<publisher>G. Grote`sche Verlagsbuchhandlung</publisher>
<pubPlace>Berlin</pubPlace>
<date>1912</date>
</bibl></sourceDesc>
</fileDesc>
<encodingDesc n="eltec-0">
<p></p>
</encodingDesc>
<profileDesc>
<langUsage>
<language ident="de">German</language>
</langUsage>
<textDesc>
<authorGender xmlns="http://distantreading.net/eltec/ns" key="M"></authorGender>
<size xmlns="http://distantreading.net/eltec/ns" key="medium"></size>
<reprintCount xmlns="http://distantreading.net/eltec/ns" key="low"></reprintCount>
<timeSlot xmlns="http://distantreading.net/eltec/ns" key="T4"></timeSlot>
</textDesc>
</profileDesc>
<revisionDesc>
<change when="2020-10-27"> I created the document. The Scan is used only to check page beginnings, paragraphs, chapters and heads.</change>
<change when="2020-11-08">I revised the document. I put "–" instead of "+"; I put "!" instead of "]". I checked the headers. In the original the chapter number 23 appears twice. I encoded a header appearing on two lines as two succesive headers as element p is not allowed.</change>
</revisionDesc>
</teiHeader>
<text>
<body>
<pb n="1"/>
<div type="liminal">
<p>Ich will hier die Geschichte des Marx Omlis erzählen.
Er ist frühauf ein Schlingel und daneben Hirt
und Jäger und Bergführer und sonst noch viel Unruhiges gewesen. In seinem Leben gibt es leichte und
schwere Kapitel und mit so bunten Gesichtern, daß man
zweifeln könnte, ob es immer der nämliche Held sei.
Aber immer schauen die gleichen Berge herein mit
langen, grauen Felsenleibern und Silberhüten auf dem
Kopf. Und immer leuchten die gleichen grünen Alpen
aus ihrem Schoß herauf und schellt und brüllt es vom
gleichen braunscheckigen Vieh um all die niedrigen Stadel
und ihre alten, steinbeschwerten Schindeldächer. Vor
allem aber dräut aus jedem Blatt immer der gleiche
wilde und schöne Kopf des Pilatus gen Himmel. Und
am Pilatus klebt und hängt das Leben des Marx Omlis
fest. Von ihm hat er sich nicht losmachen können, so
weit er auch floh. Der graue, alte Berg spielt die
Hauptrolle in seinem Leben. Er war sein Freund und
Feind, ist seine Wiege und sein Grabstein geworden.
~ Ich will mich sammeln und alles sachte und gelassen meinen lieben, besinnlichen Lesern auskramen.</p></div>
<div type="chapter">
<head>I.</head>
<p>Unser Gebirgsstädtchen hat ein Gymnasium mit
sehr weisen Lehrern, sehr tiefen Tintengeschirren und
sehr langen Sommerferien. Aber das beste von allem
sind doch die breiten, großscheibigen Fensterreihen rundum am Haus gewesen. Da drang ein unsäglich reiner,
am Horn in der andern Hand, alles hübsch nebeneinander gebettet, Mensch und Tier und Fels und
Schnee. Und weil diese Buben noch so frisch und jung
sind und darum vor dem Tod noch einen heiligen Respekt haben, so ziehen sie vor dem schönen, langen, stillen
Mann und seinem zierlichen Tier ihre Filzhüte ab und
sagen fromm: „Herr, gib ihnen die ewige Ruhe !“</p></div>
</body>
</text>
</TEI>
of which I am only interested in the "text" (body of the book), I managed to extract it from a single file with the following code:
library(XML)
library(tidyverse)
test <- "files/Federer1912_Pilatus.xml"
xmldoc <- xmlParse(test)
rootNode <- xmlRoot(xmldoc)
# rootNode[1]
data <- xmlSApply(rootNode,function(x) xmlSApply(x, xmlValue))
cd.catalog <- data.frame(t(data),row.names=NULL)
federer_1912_pilatus <- cd.catalog$text
federer_1912_pilatus <- federer_1912_pilatus[["text"]]
Is there a way to loop this operation for each of the many xml files in a specific folder, called "files"?
And eventually would it be possible to put all the extracted strings directly in a data.frame with two variables: one for the "book_name" - in which for example "federer_1912_pilatus" will appear for the text above - and one for the "text" itself?

This could be achieved like so:
Put your code in a function which takes a filename as an argument
Use list.files to get a vector of all xml files in your directory
Use e.g. lapply to loop over the files, which will return a list of your texts.
get_text <- function(fn) {
xmldoc <- xmlParse(fn)
rootNode <- xmlRoot(xmldoc)
# rootNode[1]
data <- xmlSApply(rootNode,function(x) xmlSApply(x, xmlValue))
cd.catalog <- data.frame(t(data),row.names=NULL)
x <- cd.catalog$text
x[["text"]]
}
xml_files <- list.files(path = "files", pattern = "\\.xml", full.names = TRUE)
lapply(xml_files, get_text)
EDIT Instead of looping via lapply you could make use of purrr::safely and purrr::map. This does not solve the issue with the corrupted xml files but takes care of the error. The following code will return a list res with the results for non-corrupted files and a list of the corrupted files:
get_text_safe <- purrr::safely(get_text)
texts <- purrr::map(xml_files, get_text_safe)
texts <- purrr::transpose(texts)
# Error
id_error <- map_lgl(texts$result, ~ is.null(.x))
# Results for files which are fine
res <- texts$result[!id_error]
fn_error <- xml_files[id_error]
fn_error

Related

Selecting sentences keyword-based but tokenizing into words with spacyr

I analyse political speeches and would like first parse them into sentences using spacyr. Then I would like to not only select sentences that contain certain keywords but also the ones before and after. Lastly, these texts should be tokenized into words for the following steps of quantitative text analysis.
data <- c(" frau bundesminister! österreich braucht auch in zukunft eine leistungsfähige und umweltfreundliche verkehrsinfrastruktur. es geht darum, schiene und straße gleichermaßen auszubauen, es geht darum, dass die öbb ihre hausaufgaben wahrnehmen und auch die asfinag. für uns ist ganz wichtig, dass gerade bei der asfinag unpolitisch gearbeitet wird. hinsichtlich der führung haben wir klar gemacht, dass eine verfassungsrichterin als aufsichtsratsmitglied unvereinbar ist, da der verfassungsgerichtshof regelmäßig mit verfahren in straßenverkehrsangelegenheiten befasst ist. was werden sie unternehmen, frau bundesminister, um die unabhängigkeit der rechtsprechung des verfassungsgerichtshofes, die durch die bestellung eines von ihnen politisch abhängigen verfassungsrichters höchst gefährdet ist, wiederherzustellen?")
court_tks <- spacy_tokenize(data$text,
what = "sentence",
remove_punct = TRUE,
remove_symbols = TRUE,
remove_numbers = TRUE) %>%
tokens() %>%
tokens_select(c("*verfassungsgericht*", "*vfgh*"))
This is my current code, which tokenizes in sentences and selects the sentences that contain the keywords, but I don't know how to also select the sentences before and after and tokenize into words not sentences in the end.

Umwandlung Shapefiles von LST120 zu LST100 mit Hilfe der HeTA2010.gsb bei QGIS [closed]

Closed. This question is not written in English. It is not currently accepting answers.
Stack Overflow is an English-only site. The author must be able to communicate in English to understand and engage with any comments and/or answers their question receives. Don't translate this post for the author; machine translations can be inaccurate, and even human translations can alter the intended meaning of the post.
Closed 4 days ago.
Improve this question
Ich würde gerne Daten, die noch im Gauss-Krüger Ellipsoid (EPSG:31467) projiziert sind, in UTM (EPSG:25832) umwandeln im Bereich Hessen. Also von Lagestatus 100 auf 120. Mit QGIS lässt sich aber nur ein ATKIS Gitternetz für Baden Württemberg angezeigt. Das für Hessen ist ausgegraut und sucht nach einer Datei (Heta2010.gsb) die nicht auf dem System installiert ist.
Ich habe die Datei nun in einem Archiv heruntergeladen und installiert. Die Transformation lässt sich jetzt auswählen aber spuckt anschließend folgende Fehlermeldung aus:
Kann Projekttransformation zwischen EPSG:25832 und EPSG:31467 nicht verwenden
Diese Projekt gibt eine voreingestellte Transformation zwischen EPSG:31467 - DHDN / 3-degree Gauss-Kruger zone 3 und EPSG:25832 - ETRS89 / UTM zone 32N an, die auf diesem System nicht verfügbar ist.
Diese Transformation erfordert die Gitterdatei "HeTa2010.gsb", die nicht auf dem System verfügbar ist.
Die in diesem Projekt zur Verwendung angegebene Operation ist:
+proj=pipeline +step +inv +proj=tmerc +lat_0=0 +lon_0=9 +k=1 +x_0=3500000 +y_0=0 +ellps=bessel +step +proj=hgridshift +grids=HeTa2010.gsb +step +proj=utm +zone=32 +ellps=GRS80
Wenn ich nun die Gitternetzdatei aus dem Verzeichnis installieren möchte gibt es folgende Fehlermeldung:
Konnte HeTa2010.gsb nicht nach HeTa2010.gsb kopieren. Bitte die Zugriffsrechte überprüfen und nocheinmal versuchen.
Hat jemand eine Idee wie das zu lösen wäre oder einen alternativen Ansatz parat?

Scrape <ul> with corresponding <p> tag

I have the following html snipped:
<div class="main--content">
<p> <strong>Ihre Aufgaben:</strong> </p>
<ul>
<li>Zentraler Ansprechpartner für den gesamten Mitarbeiterlebenszyklus
</li>
<li>Partnerschaft mit den Geschäftsbereichen, um innovative Lösungen für die Mitarbeitererfahrung zu implementieren und zu entwickeln
</li>
<li>Beratung zur Nachfolgeregelung, Analyse der Talentpyramide und Aufbauempfehlungen
</li>
<li>Unterstützung der Führungseffektivität durch die Bereitstellung von Analyseberichten und die Nutzung der aktuellen HR-Strategie
</li> <li>Evaluierung von HR-Richtlinien und -Prozessen
</li>
<li>Erstellen und Entwickeln neuer Aktivitäten zur Verbesserung des Mitarbeiterengagements
</li>
<li>Sicherstellen, dass der HRBP-Bereich eng mit den Geschäfts- und HR-Stakeholdern verbunden ist
</li>
<li>Tätigkeit als Moderator und innovatives Teammitglied bei der Umsetzung globaler HR-Projekte
</li>
</ul>
<p>Ihr Profil:</p>
<ul>
<li>Kaufmännische Ausbildung mit Weiterbildung als Eidg. Dipl. HR-Fachfrau/mann
</li>
<li>Mehrjährige Berufserfahrung in einer ähnlichen Funktion
</li>
<li>Effektive Präsentations- und Kommunikationsfähigkeiten
</li>
</ul>
</div>
I want to extract the title, in this case whatever is written in the p tag and the corresponding list elements.
I can get the p and ul elements from this, but I am not able to dynamically give the structure.
I work with rvest
Following chunk returns the list elements:
tmp %>% rvest::html_elements("ul > li")
[1] <li>Zentraler Ansprechpartner für den gesamten Mitarbeiterlebenszyklus</li>
[2] <li>Partnerschaft mit den Geschäftsbereichen, um innovative Lösungen für die Mitarbeitererfahrung zu implementieren und zu entwickeln</li>
And the titles:
tmp %>% rvest::html_elements("p")
[6] <p> <strong>Ihre Aufgaben:</strong> </p>
[7] <p>Ihr Profil:</p>
Is there a way to extract the list to a dataframe or list?
library(rvest)
library(purrr)
doc <- minimal_html('<div class="main--content">
<p> <strong>Ihre Aufgaben:</strong> </p>
<ul>
<li>Zentraler Ansprechpartner für den gesamten Mitarbeiterlebenszyklus
</li>
<li>Partnerschaft mit den Geschäftsbereichen, um innovative Lösungen für die Mitarbeitererfahrung zu implementieren und zu entwickeln
</li>
<li>Beratung zur Nachfolgeregelung, Analyse der Talentpyramide und Aufbauempfehlungen
</li>
<li>Unterstützung der Führungseffektivität durch die Bereitstellung von Analyseberichten und die Nutzung der aktuellen HR-Strategie
</li> <li>Evaluierung von HR-Richtlinien und -Prozessen
</li>
<li>Erstellen und Entwickeln neuer Aktivitäten zur Verbesserung des Mitarbeiterengagements
</li>
<li>Sicherstellen, dass der HRBP-Bereich eng mit den Geschäfts- und HR-Stakeholdern verbunden ist
</li>
<li>Tätigkeit als Moderator und innovatives Teammitglied bei der Umsetzung globaler HR-Projekte
</li>
</ul>
<p>Ihr Profil:</p>
<ul>
<li>Kaufmännische Ausbildung mit Weiterbildung als Eidg. Dipl. HR-Fachfrau/mann
</li>
<li>Mehrjährige Berufserfahrung in einer ähnlichen Funktion
</li>
<li>Effektive Präsentations- und Kommunikationsfähigkeiten
</li>
</ul>
</div>')
## get all p and ul elements
p_and_ul <- doc %>% html_elements("p,ul")
## which of these elements are p elements?
is_p <- p_and_ul %>% html_element("li") %>% is.na()
## for each ul element get the li children
all_li <- map(p_and_ul[!is_p], ~ html_elements(.x, "li"))
## put all results togteher
res <- vector("list", length(p_and_ul))
res[is_p] <- map_chr(p_and_ul[is_p], as.character)
res[!is_p] <- map(all_li, as.character)
unlist(res)
# [1] "<p> <strong>Ihre Aufgaben:</strong> </p>"
# [2] "<li>Zentraler Ansprechpartner für den gesamten Mitarbeiterlebenszyklus\n </li>"
# [3] "<li>Partnerschaft mit den Geschäftsbereichen, um innovative Lösungen für die Mitarbeitererfahrung zu implementieren und zu entwickeln\n </li>"
# [4] "<li>Beratung zur Nachfolgeregelung, Analyse der Talentpyramide und Aufbauempfehlungen\n </li>"
# [5] "<li>Unterstützung der Führungseffektivität durch die Bereitstellung von Analyseberichten und die Nutzung der aktuellen HR-Strategie\n </li>"
# [6] "<li>Evaluierung von HR-Richtlinien und -Prozessen\n </li>"
# [7] "<li>Erstellen und Entwickeln neuer Aktivitäten zur Verbesserung des Mitarbeiterengagements\n </li>"
# [8] "<li>Sicherstellen, dass der HRBP-Bereich eng mit den Geschäfts- und HR-Stakeholdern verbunden ist\n </li>"
# [9] "<li>Tätigkeit als Moderator und innovatives Teammitglied bei der Umsetzung globaler HR-Projekte\n </li>"
# [10] "<p>Ihr Profil:</p>"
# [11] "<li>Kaufmännische Ausbildung mit Weiterbildung als Eidg. Dipl. HR-Fachfrau/mann\n </li>"
# [12] "<li>Mehrjährige Berufserfahrung in einer ähnlichen Funktion\n </li>"
# [13] "<li>Effektive Präsentations- und Kommunikationsfähigkeiten\n </li>"

R/Tesseract for multiple columns: How can I recognize different parts of a text?

I have scans of some thousand pages of an old swiss computer magazine and am going to make it public as a part of my Masters Thesis. But first I want to do an OCR with R/Tesseract on all the pages and then maybe play around with quanteda.
At this point, I am running a loop that converts the pages to pdf and png, reads ocr and creats a txt file from it. This works pretty well and all the files are converted.
However, as I'm working with a magazine all the pages are structured differently. I have advertising, single columns multiple columns, etc. I cannot make Tesseract recognize the columns and even if it gives me the parting lines (which it does sometimes) I cannot figure out how to structure it the right way.
I'm using this for the OCR:
file <- images_test %>%
image_convert(type = 'Grayscale') %>%
image_write(format = 'png')
text <- tesseract::ocr(file, engine = tesseract("deu"))
write(text, file = txtpfad)
And my results look like this:
RUND UM DEN IBM-PC 2 IN Ir ne Bytes pro Sektor. Mit der Datenüber- Gruppe von schnellen Arbeitsplatz- estate von 250 Kbits/Sekunde ISSCO
Software rechnern besteht eine separate können die 10 MB in acht
Minuten f d DE Be Sr aufgezeichnet oder rückgelesen wer- nfo: ultitec
: an . (streaming mode/Einmaldurch- au em neuen Bar 66, 3000 Bern 22,
Tel. 4 lauf). Die drei weiteren Modelle des C . Produktprogrammes
(Irwin 120, 125 IBM RT P und 325) haben pro Datenkassette .. = sogar
eine Kapazität von 20 MB. Die erhältlich einzelnen Einheiten
unterscheiden AT A a l sich jeweils in der Uebertragungsge- von pica
schwindigkeit, der Gerätegrösse und Die Freigabe der 32-Bit Work- in
der Art des Aufbaus (Einbau- oder | station von IBM (amerikanische Die
Personal Computer der AT Peripherie-Gerät) Bezeichnung: IBM RT PC)
erfolg- | Serie von APICAL erfüllen alle Die beiden Einbaumodelle
(Irwin | te erst kürzlich. Schon meldet | Anforderungen, die heute an
ei- 120 und 125) werden wiederum di- | MULTITEC, dass die auf Gross- |
nen IBM-AT Kompatiblen gestellt rekt an den im PC eingebauten Flop- |
rechnern und Minicomputern | werden. Und mehr. Sie sind nicht
py-Kontroller angeschlossen. Da die | verbreiteten Grafik-Software- |
nur kompatibel, sondern, wie Datentransferrate dieser beiden Ge- |
Pakete DISSPLA, TELL-A-GRAF, | es sich für einen Rechner der räte bei
500 Kbits/Sekunde liegt, | TELLAPLAN und CUECHART | Spitzenklasse
gehört, obendrein werden die 20 MB in nur knapp neun | jetzt auch auf
(...)
Found a solution. Tesseract has A LOT of options I have never heard of before. You have to set up your engine the right way first.
deu <- tesseract(language = "deu", options = list(tessedit_pageseg_mode = 1))
text <- ocr(file,engine = deu)
There is still a potential for improvement but it looks a lot better now.

sub in R Corpus

I downloaded files such as this one to put in a corpus, all including text like
"Deutscher Bundestag
Stenografischer Bericht
Sitzung
Berlin, Freitag, den 11. November 2016
Inhalt
Tagesordnungspunkt 36:
Dritte Beratung des von der Bundesregierung eingebrachten Entwurfs eines Vierten Gesetzes zur Änderung arzneimittelrechtlicher und anderer Vorschriften
Drucksachen 18/8034, 18/8333, 18/8461 Nr. 1.5, 18/10280, 18/10056
Präsident Dr. Norbert Lammert: Nehmen Sie bitte Platz. Die Sitzung
ist eröffnet. Liebe Kolleginnen und Kollegen, ich begrüße Sie"
I want to cut off all text up to the start of the parliamentary debate.
If I do
test <- c("text from above")
test <- sub(".*Die Sitzung ist eröffnet\\.","",test)
That works, but if I use
for (j in seq(test))
{
test[[j]] <- sub(".*Die Sitzung ist eröffnet\\.","",test[[j]])
}
for the Corpus I don't get any kind of change. Help is much appreciated, thank you!

Resources