2016-03-07 3 views
1

Я пытаюсь проанализировать существующий документ и изменить его, обернув div вокруг некоторых существующих элементов формы.Как я могу обернуть div вокруг существующих элементов?

HTML форма выглядит как это:

<form> 
    <label for="username">Username:</label> 
    <input name="username" type="text" /> 
    <label for="password">Password:</label> 
    <input name="password" type="password" /> 
</form> 

Я могу разобрать документ ОК с Nokogiri и я знаю о методе wrap но я изо всех сил, чтобы понять, как выбрать метку и введите теги за один раз, а затем оберните div вокруг них. Так что результат я ищу это:

<form> 
    <div class="form-group"> 
    <label for="username">Username:</label> 
    <input name="username" type="text" /> 
    </div>  
    <div class="form-group"> 
    <label for="password">Password:</label> 
    <input name="password" type="password" /> 
    </div> 
</form> 

Я пробовал различные XPaths/CSS селекторы и может создать набор узлов просто этикетки/входы или все из элементов всей формы. Есть ли способ достичь этой модификации?

+1

Добро пожаловать в SO. Пожалуйста, прочитайте «[ask]» и «[mcve]». Мы не можем сказать, что вы пробовали. Нам лучше исправить ваш код, чем нам писать совершенно несвязанный код, и вы пытаетесь его закрепить. Какие «различные XPaths/CSS selectors» вы пишете? Как вы использовали их с Нокогири? –

ответ

2

Одно выражение XPath может возвращать только одну коллекцию узлов, поэтому для достижения того, что вы хотите, вам нужно будет сделать несколько запросов, по одному для каждой пары label - input.

Вы можете выбрать отдельную пару с чем-то вроде этого, предполагая, что разметка хорошо вела себя (т.е. каждый input имеет label перед ним):

//label[1] | //label[1]/following-sibling::input[1] 

Это будет выбрать первый label и следующий input. Однако вы хотите выбрать все такие пары. Один из способов - сначала выбрать все узлы label, а затем выбрать для каждого label его и следующий вход.

labels = doc.xpath("//form/label") 
labels.each do |l| 
    nodes = l.xpath(". | ./following-sibling::input[1]") 
    # nodes now contains a label-input pair... 
end 

Я не думаю, что метод wrap будет работать, чтобы добавить div элемент в качестве предка для каждой пары, как это добавит элемент каждый члена множества узлов. Вы, вероятно, придется переместить их вручную, что-то вроде

labels = doc.xpath("//form/label") 
labels.each do |l| 
    # Select this node and its neighbour. 
    nodes = l.xpath(". | ./following-sibling::input[1]") 

    # Create the new element, and add it before the label. 
    div = Nokogiri::XML::Node.new('div', l.document) 
    l.before(div) 

    # Move each of the pair onto this new element. 
    nodes.each do |n| 
    div.add_child(n) 
    end 
end 

Обратите внимание, что этот метод не перемещать любые текстовые узлы, так что вы можете обнаружить пробелы вашего документа изменений немного.

+0

Спасибо. Я видел пару ответов на другие подобные запросы, но я думаю, что ваше решение является кратким и имеет смысл для этой конкретной ситуации. Приветствия. –