【问题标题】:Create multiple XML2 filtering from a single XML从单个 XML 创建多个 XML2 过滤
【发布时间】:2019-05-14 15:44:01
【问题描述】:

使用 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 库解决问题的更好方法吗?

谢谢!

【问题讨论】:

    标签: r xml xml2


    【解决方案1】:

    xml_remove 将从您找到它们的文档中删除节点。在完成 find_all 之后交换 XML 的值并没有真正的帮助,因为它们仍然指向原始文档。复制文档的一种方法似乎是带有.copy=TRUE 参数集的xml_new_root 函数。这是一个可以帮助您完成任务的函数

    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")
    

    所以我们在这里制作副本,然后在该副本中找到节点,然后删除它们。这里我改为!=比较,只保留传入语言的值。

    【讨论】:

      【解决方案2】:

      考虑一下XSLT,这是一种专用语言,旨在将您传递语言参数的 XML 文件 enit 从 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);
      

      【讨论】:

      • 感谢您的努力!我以后会深入研究XLST,现在在我的真实案例中使用它可能会有点痛苦!但是 XLST 看起来对我的东西很有希望
      • 明白。 XSLT 确实需要一些诀窍,但传递参数值非常酷。这是我第一次在 R 中这样做,所以谢谢你的提问。我正在将此添加到我的解决方案库中。
      猜你喜欢
      • 2017-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多