使用 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 库解决该问题的更好方法?
谢谢!
答案 0 :(得分:1)
xml_remove
将从您在其中找到节点的文档中删除这些节点。完成find_all之后交换掉XML
的值实际上并没有帮助,因为它们都仍然指向原始文档。复制文档的一种方法似乎是使用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")
因此,在这里我们制作副本,然后在该副本中找到节点,然后将其删除。在这里,我更改为!=
比较,以仅保留所传递语言的值。
答案 1 :(得分:0)
考虑XSLT,这是一种专用语言,旨在转换XML文件,您可以在其中将语言参数 en 和 it 从R传递到XSLT。 R可以使用xslt
软件包(扩展名为xml2
)运行XSLT 1.0脚本。
具体来说,您可以使用相同的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);