Создать несколько фильтров XML2 из одного XML - PullRequest
2 голосов
/ 14 мая 2019

С пакетом xml2 Я хочу написать два XML-файла - один для языка - начиная с одного XML-файла. Например, у меня есть следующий XML-файл:

<?xml version="1.0" encoding="UTF-8"?>
<books>
  <book>
    <title xml:lang="it">Title IT</title>
    <title xml:lang="en">Title EN</title>
    <author>Author</author>
  </book>
</books>

и я хочу сохранить следующие два файла:

FILE IT
<?xml version="1.0" encoding="UTF-8"?>
<books>
  <book>
    <title xml:lang="it">Title IT</title>
    <author>Author</author>
  </book>
</books>

FILE EN
<?xml version="1.0" encoding="UTF-8"?>
<books>
  <book>
    <title xml:lang="en">Title EN</title>
    <author>Author</author>
  </book>
</books>

Если я сделаю следующее:

txt <- "<books><book><title xml:lang='it'>Title IT</title><title xml:lang='en'>Title EN</title><author>Author</author></book></books>"
XML <- xml2::read_xml(txt)

it <- xml2::xml_find_all(XML, "//*[@xml:lang = 'it']")
en <- xml2::xml_find_all(XML, "//*[@xml:lang = 'en']")


XML_orig <- XML
xml2::xml_remove(en)
xml2::write_xml(XML, file = "book_it.xml")

XML <- XML_orig
xml2::xml_remove(it)
xml2::write_xml(XML, file = "book_en.xml")

Когда я создаю копию объекта XML, он продолжает ссылаться на исходный. Есть ли способ создать новую копию без ссылок? Или вы знаете лучший способ решения вопроса, используя библиотеку xml2 ?

Спасибо!

Ответы [ 2 ]

1 голос
/ 14 мая 2019

xml_remove удалит узлы из документа, в котором вы их нашли. Замена значения XML после выполнения команды find_all не очень помогает, поскольку они все еще указывают на исходный документ. Одним из способов дублирования документа является функция xml_new_root с набором параметров .copy=TRUE. Вот функция, которая может помочь с вашей задачей

keeplang <- function(XML, lang) {
  nodepath <- paste0("//*[@xml:lang != '", lang, "']")
  filepath <- paste0("book_", lang, ".xml")
  XML <- xml_new_root(XML, .copy = TRUE)  
  nodes <- xml2::xml_find_all(XML, nodepath)
  xml2::xml_remove(nodes)
  xml2::write_xml(XML, file = filepath)
}

keeplang(XML, "it")
keeplang(XML, "en")

Итак, здесь мы создаем копию, затем находим узлы в этой копии, а затем удаляем их. Здесь я изменил != сравнение, чтобы сохранить только значения для переданного языка.

0 голосов
/ 14 мая 2019

Рассмотрим XSLT , язык специального назначения, предназначенный для преобразования файлов XML, в который передаются языковые параметры, en и it из R в XSLT.R может запускать сценарии XSLT 1.0, используя пакет xslt (расширение xml2).

В частности, вы можете использовать тот же сценарий XSLT, передавая значения из R для определенных title узлов.Это мало чем отличается от передачи параметров другому известному языку специального назначения: SQL.Прелесть также в том, что XSLT является переносимым (опять же как SQL) и может быть запущен за пределами R, чтобы получить тот же результат.

XSLT сохранить как файл .xsl, специальный файл .xml)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:param name="lang" />

  <!-- IDENTITY TRANSFORM -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="book">
    <xsl:copy>
        <xsl:copy-of select="title[@xml:lang = $lang]"/>
        <xsl:copy-of select="author"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

R

library(xml2)
library(xslt)

doc <- read_xml("Input.xml", package = "xslt")
style <- read_xml("Script.xsl", package = "xslt")

# en LANGUAGE
new_xml <- xml_xslt(doc, style, params=list(lang="en"))   
write_xml(new_xml, "Output_en.xml")

# it LANGUAGE
new_xml <- xml_xslt(doc, style, params=list(lang="it"))   
write_xml(new_xml, "Output_it.xml")

Python (для демонстрации мобильности)

import lxml.etree as et

# LOAD XML AND XSL SCRIPT
xml = et.parse('Input.xml')
xsl = et.parse('Script.xsl')
transform = et.XSLT(xsl)

# PASS en PARAMETER TO XSLT
n = et.XSLT.strparam("en")
result = transform(xml, lang=n)

with open("Output_en.xml", 'wb') as f:
    f.write(result)

# PASS it PARAMETER TO XSLT
n = et.XSLT.strparam("it")
result = transform(xml, lang=n)

with open("Output_it.xml", 'wb') as f:
    f.write(result)

PHP

// LOAD XML AND XSLT
$xml = new DOMDocument('1.0', 'UTF-8');
$xml->load('Input.xml');

$xsl = new DOMDocument('1.0', 'UTF-8');   
$xsl->load('Script.xsl');

// INITIALIZE TRANSFORMER
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);

// SET en PARAMETER VALUE
$proc->setParameter('', 'lang', 'en');
$newXML = $proc->transformToDoc($xml);
file_put_contents('Output_en.xml', $newXML);

// SET en PARAMETER VALUE
$proc->setParameter('', 'lang', 'it');
$newXML = $proc->transformToDoc($xml);
file_put_contents('Output_it.xml', $newXML);
...