如何使多个标题的一个列表



我有这个XML字符串:

xml = "<name>Married with Children</name>
<person age="20">Al Bundy</person>
<character age="20">Bud Bundy</character>
<character age="19">Marcy Darcy</character>
<person age="18">John Doe</person>"

我明白如果我使用

xml.css("characters")

它会生成一个带有字符标记的标题列表,类似于

[<character age="20">Bud Bundy</character>, <character age="19">Marcy Darcy</character>]

我只是想去掉name标签,所以我想:

[<person age="20">Al Bundy</person>, 
 <character age="20">Bud Bundy</character>, 
 <character age="19">Marcy Darcy</character>, 
 <person age="18">John Doe</person>]

是否有一种方法来创建一个人或字符标记的列表?

你的问题有很多问题,但我会试着把它们整理出来,这样你就能明白发生了什么,以及如何在将来写出更好的问题。

  1. 您的XML示例格式不正确:

    xml = "<name>Married with Children</name>
    <person age="20">Al Bundy</person>
    <character age="20">Bud Bundy</character>
    <character age="19">Marcy Darcy</character>
    <person age="18">John Doe</person>"
    -:3: syntax error, unexpected tINTEGER, expecting end-of-input
    <person age="20">Al Bundy</person>
    

    你得到这个是因为你有外部双引号,和双引号包装的参数。在提问时,确保样本数据是可用的是很重要的。它应该看起来像:

    xml = '<name>Married with Children</name>
    <person age="20">Al Bundy</person>
    <character age="20">Bud Bundy</character>
    <character age="19">Marcy Darcy</character>
    <person age="18">John Doe</person>'
    

    或者:

    xml = <<EOT
    <name>Married with Children</name>
    <person age="20">Al Bundy</person>
    <character age="20">Bud Bundy</character>
    <character age="19">Marcy Darcy</character>
    <person age="18">John Doe</person>
    EOT
    

    此时Ruby将允许您开始测试代码。

  2. 您的示例XML没有根节点。XML有严格的定义,因此,提供正确的数据非常重要:

    require 'nokogiri'
    xml = '<name>Married with Children</name>
    <person age="20">Al Bundy</person>
    <character age="20">Bud Bundy</character>
    <character age="19">Marcy Darcy</character>
    <person age="18">John Doe</person>'
    doc = Nokogiri::XML(xml)
    doc.to_xml # => "<?xml version="1.0"?>n<name>Married with Children</name>n"
    

    如果我使用doc.errors Nokogiri会告诉我为什么它只有一个节点:

    doc.errors # => [#<Nokogiri::XML::SyntaxError: Extra content at the end of the document>]
    
    有两种方法可以解决这个问题,添加一个换行根节点,或者告诉Nokogiri将标记视为文档的一个片段:
    doc = Nokogiri::XML('<root>' + xml + '</root>')
    doc.to_xml # => "<?xml version="1.0"?>n<root><name>Married with Children</name>n<person age="20">Al Bundy</person>n<character age="20">Bud Bundy</character>n<character age="19">Marcy Darcy</character>n<person age="18">John Doe</person></root>n"
    

    或:

    doc = Nokogiri::XML::DocumentFragment.parse(xml)
    doc.to_xml # => "<name>Married with Children</name>n<person age="20">Al Bundy</person>n<character age="20">Bud Bundy</character>n<character age="19">Marcy Darcy</character>n<person age="18">John Doe</person>"
    

    请注意解析后两个dom之间的区别。第一个包含节点,第二个只包含样例XML中的节点。

    既然DOM没有错误,就可以开始解析和收集数据了。如果您不能确保DOM被正确解析,那么您可能会发现Nokogiri对DOM进行了修正和修改,以使其在语法上正确,从而产生与您期望的不同的结构。太频繁地处理这些会让你发疯的。

  3. 在搜索时使用正确的标签名称。这是不言自明的,因为你要么得到一个结果,要么得到nil或一个空的NodeSet ([]):

    doc = Nokogiri::XML('<root>' + xml + '</root>')
    data = doc.css('characters') # => []
    data.class # => Nokogiri::XML::NodeSet
    data = doc.at_css('characters') # => nil
    

    而我们想要的是:

    data = doc.css('character') # => [#<Nokogiri::XML::Element:0x3fc8c4c4d598 name="character" attributes=[#<Nokogiri::XML::Attr:0x3fc8c4c4d4bc name="age" value="20">] children=[#<Nokogiri::XML::Text:0x3fc8c4c4c544 "Bud Bundy">]>, #<Nokogiri::XML::Element:0x3fc8c4c49d44 name="character" attributes=[#<Nokogiri::XML::Attr:0x3fc8c4c49ce0 name="age" value="19">] children=[#<Nokogiri::XML::Text:0x3fc8c4c49830 "Marcy Darcy">]>]
    data = doc.at_css('character') # => #<Nokogiri::XML::Element:0x3fc8c4c4d598 name="character" attributes=[#<Nokogiri::XML::Attr:0x3fc8c4c4d4bc name="age" value="20">] children=[#<Nokogiri::XML::Text:0x3fc8c4c4c544 "Bud Bundy">]>
    

    或使用泛型方法:

    data = doc.search('character') # => [#<Nokogiri::XML::Element:0x3fe8fe0771d8 name="character" attributes=[#<Nokogiri::XML::Attr:0x3fe8fe076ff8 name="age" value="20">] children=[#<Nokogiri::XML::Text:0x3fe8fe07633c "Bud Bundy">]>, #<Nokogiri::XML::Element:0x3fe8fe07606c name="character" attributes=[#<Nokogiri::XML::Attr:0x3fe8fe073fd8 name="age" value="19">] children=[#<Nokogiri::XML::Text:0x3fe8fe073b50 "Marcy Darcy">]>]
    data = doc.at('character') # => #<Nokogiri::XML::Element:0x3fe8fe0771d8 name="character" attributes=[#<Nokogiri::XML::Attr:0x3fe8fe076ff8 name="age" value="20">] children=[#<Nokogiri::XML::Text:0x3fe8fe07633c "Bud Bundy">]>
    

    请注意,at及其at_cssat_xpath兄弟姐妹相当于search('for something').first

让我们来看看获取所需数据的一种方法:您可以使用CSS的,操作符来查找多个不同的节点:

data = doc.search('character, person') # => [#<Nokogiri::XML::Element:0x3fd7de018c7c name="person" attributes=[#<Nokogiri::XML::Attr:0x3fd7de018b8c name="age" value="20">] children=[#<Nokogiri::XML::Text:0x3fd7de015b80 "Al Bundy">]>, #<Nokogiri::XML::Element:0x3fd7de014fb4 name="character" attributes=[#<Nokogiri::XML::Attr:0x3fd7de014dd4 name="age" value="20">] children=[#<Nokogiri::XML::Text:0x3fd7de014550 "Bud Bundy">]>, #<Nokogiri::XML::Element:0x3fd7de014294 name="character" attributes=[#<Nokogiri::XML::Attr:0x3fd7de01421c name="age" value="19">] children=[#<Nokogiri::XML::Text:0x3fd7de011d00 "Marcy Darcy">]>, #<Nokogiri::XML::Element:0x3fd7de011a94 name="person" attributes=[#<Nokogiri::XML::Attr:0x3fd7de011a30 name="age" value="18">] children=[#<Nokogiri::XML::Text:0x3fd7de0112d8 "John Doe">]>]
data.map(&:to_xml) # => ["<person age="20">Al Bundy</person>", "<character age="20">Bud Bundy</character>", "<character age="19">Marcy Darcy</character>", "<person age="18">John Doe</person>"]

可以工作,但是您不能完全控制获得结果节点的顺序,而是按照它们在文档中出现的顺序。如果你想控制这个顺序,你可能会想要做两个单独的搜索,然后连接节点集。如何做那件事就留给你自己去想了。

要解析XML或HTML,很重要的是要理解CSS和/或XPath选择器。我建议专注于CSS选择器,因为它们通常更具可读性。此外,为了方便使用,Nokogiri实现了许多jQuery的CSS扩展,这增加了简单性的功能。XPath要强大得多,但代价是大量的视觉干扰。尽管如此,您还是希望熟悉它,以便在必要时从工具箱中取出该工具。

您可以使用简单的选择器,然后在Nokogiri中折叠/旋转/破坏结果,但是使用libXML的强大功能需要通过选择器向它提供信息,因此学习如何有效和正确地使用它们非常重要。让Nokogiri和libXML完成繁重的工作之间的速度差异将很快使您相信这一点。

相关内容

  • 没有找到相关文章

最新更新