2016-08-13 40 views
-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>" 

我明白,如果我用

xml.css("characters") 

的字符标记头它会产生一个列表,像

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

我只想摆脱名称标签,所以我想:

[<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.css(“characters”)'''''''''''''''''''除了'['''''没有''标签以外。 'css。('character')'会找到两个节点。另外,您的XML在语法上不正确,因为它缺少一个根节点。请阅读“[问]”和“[mcve]”。你尝试了什么?我们需要看到你的努力的证据。没有它,看起来你希望我们为你写代码。 –

回答

1

你的问题有多个问题,但我会尝试整理出来,以便你了解正在发生的事情以及将来如何写出更好的问题。

  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 
    

    此时红宝石将让你开始测试你的代码。

  2. 您的示例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>] 
    

    有固定两种方式XML有严格的定义,以便再次,它提供正确的数据是非常重要的此,添加一个包裹根节点,或者告诉引入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. 搜索时使用正确的标签名称。这是不言自明的,你会要么得到的结果或将获得零或空节点集([]):

    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兄弟姐妹是相当于。

移动到一个方法来获得数据,你想:你可以使用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>"] 

这样的作品,但是你没有总量控制的顺序你会得到结果节点,而不是他们在文件中出现的顺序。如果你想控制这个顺序,你可能会想要做两个单独的搜索,然后连接NodeSets。如何做到这一点,留给你弄清楚。

要解析XML或HTML,理解CSS和/或XPath选择器很重要。我建议专注于CSS选择器,因为它们通常更具可读性。另外,Nokogiri实现了许多jQuery的CSS扩展,以方便使用,从而增加了简单性。 XPath功能强大得多,但价格很高,视觉噪声很大。但是,您仍然需要熟悉它,以便在必要时从工具箱中取出该工具。

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

+0

一个英雄的答案,特别是考虑到问题的问题。 –

+0

@WayneConrad,heh,是的,那里的“英雄”意味着啰嗦。 :-) –

+0

即使我投票结束这个问题,我投了赞成这个答案。它值得。我希望OP能够将问题编辑成形。 –