2016-12-16 2 views
0

У меня есть дамп XML и я пытаюсь его проанализировать с помощью Nokogiri, чтобы получить текстовое значение атрибута, а затем выяснить, соответствует ли он определенной строке, которую я ищу. Вот отрывок из моего файла XML:Получение значения атрибута и тестирование его с помощью Nokogiri

 #(Element:0x3fc58cc091f8 { 
     name = "host", 
     attributes = [ #(Attr:0x3fc58cc08528 { name = "starttime", value = "1481896934" }), #(Attr:0x3fc58cc08514 { name = "endtime", value = "1481896947" })], 
     children = [ 
     #(Element:0x3fc58af6bdc0 { 
      name = "status", 
      attributes = [ 
      #(Attr:0x3fc58af6b6f4 { name = "state", value = "up" }), 
      #(Attr:0x3fc58af6b6e0 { name = "reason", value = "arp-response" }), 
      #(Attr:0x3fc58af6b6cc { name = "reason_ttl", value = "0" })] 
      }), 
     #(Text "\n"), 
     #(Element:0x3fc58a744fe8 { 
      name = "os", 
      children = [ 
      #(Element:0x3fc58c1392f0 { 
       name = "osmatch", 
       attributes = [ 
       #(Attr:0x3fc58c1381d4 { name = "name", value = "Microsoft Windows XP SP2 or SP3, or Windows Server 2003" }), 
       #(Attr:0x3fc58c1381c0 { name = "accuracy", value = "100" }), 
       #(Attr:0x3fc58c1381ac { name = "line", value = "57766" })], 
       children = [ 
       #(Text "\n"), 
       #(Element:0x3fc58ae89e70 { 
        name = "osclass", 
        attributes = [ 
        #(Attr:0x3fc58ae893bc { name = "type", value = "general purpose" }), 
        #(Attr:0x3fc58ae893a8 { name = "vendor", value = "Microsoft" }), 
        #(Attr:0x3fc58ae89394 { name = "osfamily", value = "Windows" }), 
        #(Attr:0x3fc58ae89380 { name = "osgen", value = "XP" }), 
        #(Attr:0x3fc58ae8936c { name = "accuracy", value = "100" })], 
        children = [ #(Element:0x3fc58b19428c { name = "cpe", children = [ #(Text "cpe:/o:microsoft:windows_xp")] })] 
        }), 
       #(Text "\n"), 

Итак, что я пытаюсь сделать, это получить содержимое os/osmatch/@name.value. В этом случае это будет Windows XP SP2 or SP3, or Windows Server 2003.

Я получил эту часть вниз:

doc.xpath("//host").each do |host| 
    os = host.at_xpath("os/osmatch").at_xpath("@name").value rescue nil 
end 

output: Microsoft Windows XP SP2 or SP3, or Windows Server 2003 

Обычно мой файл XML будет иметь тонн хостов с различными операционными системами, хотя, так что выход будет вероятно выглядеть примерно так:

Microsoft Windows XP SP2 or SP3, or Windows Server 2003 
Ubuntu 14.04 Linux 
Microsoft Windows 7, or Microsoft Windows 8 
FreeBSD X.X.X 
.... 

То, что я пытаюсь сделать, это сопоставить определенные строки с значениями, которые я ищу сейчас, поэтому я могу сделать некоторые действия, если, например, найдено Windows XP.

doc.xpath("//host").each do |host| 
    os = host.at_xpath("os/osmatch").at_xpath("@name[contains(value, 'Windows XP')]") 
end 

Но вместо этого у меня возникает ошибка, поэтому я знаю, что я делаю что-то неправильно. Я пробовал некоторые другие варианты, но не могу понять, как это сделать:

Nokogiri::XML::XPath::SyntaxError: Invalid expression: @name[contains(value, 'Windows'] 
+1

Вероятно, вы должны привести пример фактического XML, а не результат анализируемого результата, чтобы люди могли воспроизводить ваши проблемы и тестовые решения. – matt

+0

@matt Извините ... это было очень долго. пытаясь спасти глаза! – Godzilla74

+1

«Это было очень долго, пытаясь спасти глаза!» Пожалуйста, прочитайте «[mcve]». Мы ценим настроение, но вам нужно лишить входной XML до минимальной суммы, которая демонстрирует проблему до публикации. Этот процесс снятия кода и ввода часто выявляет проблему для вас без необходимости задавать вопрос. И, как сказал @matt, XML полезен для нас. Проверенный DOM не так полезен, поскольку мы не можем его повторно использовать для тестирования решений. Что это значит, нам нужно, чтобы вы помогли нам помочь вам. –

ответ

0
host.at_xpath("os/osmatch[contains(@name,'Windows')]") 
+0

Хорошо, так что возвращает весь элемент. Мне просто нужно вернуть значение '@ name'. – Godzilla74

+0

Запросите его так же, как и вы. Это элемент xpath. – mudasobwa

+0

Ах, ухо! Благодаря! – Godzilla74

1

Вы, кажется, смешиваясь Xpath и Ruby, код. Ваш рабочий код является

at_xpath("@name").value 

Здесь @name является запрос XPath, и это возвращает Node объект в Ruby. Этот объект имеет метод value, который возвращает значение атрибута в виде строки, но value is не действительный XPath.

Вы пытаетесь изменить, добавив предикат:

at_xpath("@name[contains(value, 'Windows XP')]") 

Здесь вы пытаетесь использовать метод рубин value в XPath. Это не работает. Однако, в XPath можно использовать . (т.е. точка), чтобы выбрать текущий узел, и это то, что вы хотите здесь:

at_xpath("@name[contains(., 'Windows XP')]") 

Это даст вам атрибут name текущего узла (вещь вы» re вызывает at_xpath), если он содержит строку «Windows XP».