2013-10-18 2 views
1

다음은 달성하려는 변환의 예입니다. 소스 XML :Ruby에서 스마트 태그 그룹으로 XML 구문 분석

<cats> 
    <cat>John</cat> 
    <cat>Peter</cat> 
</cats> 

결과 : I 소스 XML에 단 하나의 <cat>이 경우에도 배열로 해시 결과에 'cats'의 값을 싶습니다

{'cats' => ['John', 'Peter']} 

합니다.

그래서,이 규칙을 적용 파서 싶습니다

노드 xyzs이 이름 xyz (및 다른 노드)와 하나 개 이상의 자식 노드를 포함하면, 노드 xyzs는로 표현되어야한다 배열의 각 요소는 xyz 요소의 내용이어야합니다. 여기

그것이 XmlSimple LIB 사용하여 달성 할 수있는 방법이다 : 그러나

XmlSimple.xml_in('cats.xml',{:forcearray=>['cat'], :grouptags=>{"cats"=>"cat"}}) 

을, 나는 대상의 모든 요소 이름에 넣어해야하고, forcearray을 정의하는 다른 방법이없는 것 같습니다/XmlSimple 내 grouptags 동작.

모든 이름을 추출한 다음 xml_in 메서드로 전달하는 사전 처리 루틴을 해킹하는 것은 어렵지 않지만 이렇게하려면 좀 더 우아한 (즉, 이미 작성된) 방법이있을 것입니다. 이 문제라면, 내 최종 목표는 MongoDB를에 결과 해시를 저장하는 것입니다 :


UPD (I는 다른 XML 파싱 LIB 그것을 할 수있는 변환의 경우를 사용하여 드리겠습니다) (즉, 전체 변환은 XML입니다 -> BSON)


UPD2 : 다시, NOT 승 요소의 이름을 지정하려면 나는 DO hich는 배열로 취급되어야하며, lib가 나에게 마법을 부탁하고 싶습니다.

require 'inflector' 
require 'nokogiri' 

def get_xml_stuff(xml, singular) 
    plural = Inflector.pluralize(singular) 
    return_hash = {plural => []} 
    xml.xpath("*/#{plural}/#{singular}").each { |tag| return_hash[plural] << tag.text} 
    return return_hash 
end 

이 내 테스트에 따라, 당신의 XmlSimple 코드를 일치하는 간단한 사건을 해결 : 노코 기리를 사용

+0

는 숙제처럼 소리. –

+0

"lib 찾기 ..."로 시작하는 할당이 너무 많지 않습니다. – vorou

답변

1

, 우리는이 코드를 작성할 수 있습니다.

노드 xyzs 이름 xyzs으로, 다음 노드 xyzs이 해시 결과의 배열로 표현해야한다 이름 xyz (및 다른 노드)와 하나 개 이상의 자식 노드를 포함하는 경우 (각 : 당신의 추가 요구 사항에 대한 배열 요소는 해당 xyz 요소의 내용이어야합니다. 같은 복수 번 파일에서 여러 차례 나타나는 경우,하지만 아직 완벽 하진

def get_xml_stuff(xml, singular) 
    plural = Inflector.pluralize(singular) 
    return_hash = {plural => []} 
    path = xml.xpath("*/#{plural}/#{singular}") 
    path.each { |tag| return_hash[plural] << tag.text} unless path.size != xml.xpath("*/#{plural}/*").children.size 
    return return_hash 
end 

.


UPD2 응답. 여기

def get_xml_stuff(xml, plural) 
    singular = Inflector.singularize(plural) 
    return_hash = {plural => []} 
    path = xml.xpath("./#{singular}") 
    path.each { |tag| return_hash[plural] << tag.text} unless path.size != xml.xpath("./*").size 
    return return_hash 
end 

우리가 복수의 부모 노드에서 시작, 모든 명명 된 아이들이 그 단수 이름의 경우 모든 단일 어린이 노드를 수집 다음과 같이 함수의 나의 새로운 버전입니다. 나의 새로운 테스트 코드가된다 :

sample_xml = Nokogiri::XML(sample_xml_text) 
sample_xml.children.xpath("*").each do |child| 
    array = get_xml_stuff(child, child.name) 
    p array 
end 

내 예를 <pets> 같은 태그가없는 경우, 다음과 같은 작업을해야합니다 :

sample_xml = Nokogiri::XML(sample_xml_text) 
array = get_xml_stuff(sample_xml.children.first, sample_xml.children.first.name) 
p array 

끝 참고로 UPD2


, 내 테스트 :

sample_xml_text = <<-sample 
<pets> 
    <cats> 
    <cat>John</cat> 
    <cat>Peter</cat> 
    </cats> 
    <kitties> 
    <kitty>Tibbles</kitty> 
    <kitty>Meow-chan</kitty> 
    <kitty>Puss</kitty> 
    </kitties> 
    <giraffes> 
    <giraffe>Long Neck</giraffe> 
    </giraffes> 
    <dogs> 
    <dog>Rover</dog> 
    <dog>Spot</dog> 
    <cat>Peter</cat> 
    </dogs> 
</pets> 
sample 

sample_xml = Nokogiri::XML(sample_xml_text) 
array = get_xml_stuff(sample_xml, "cat") 
p array 
array = get_xml_stuff(sample_xml, "kitty") 
p array 
array = get_xml_stuff(sample_xml, "giraffe") 
p array 
array = get_xml_stuff(sample_xml, "dog") 
p array 
s로 끝나는
+0

UPD2를 참조하십시오. 요소 이름을 지정하고 싶지 않습니다. – vorou

1

먼저 찾기 요소 이름 :

names = doc.search('*[name()$="s"]').map(&:name).uniq 
#=> ["cats"] 

나머지는 단지 매핑되고 해싱 :

Hash[names.map{|name| [name, doc.search("#{name} > #{name.sub /s$/, ''}").map(&:text)]}] 
#=> {"cats"=>["John", "Peter"]} 
+0

좋은 소식! 하지만 각 요소의 콘텐츠를 해시로 가져올 수 있습니까? 즉, 어떻게 ' – vorou

+0

나는거야 {'고양이 '[> 10 {'이름 '=>'존 ','나이 '=}]은 =>이}'에' 10'를 켭니다 힌트를 주면'(& : text)'를'{| x | Hash [x.search ('> *'). map (something else)]}' – pguardiario