2016-03-10 34 views
0

我試圖根據xml文件中的標記數量來獲取一個命令來提取幾個字符串。我有這樣的文件結構:Bash提取特定標記之間的所有行

<task id="0"> 
some stuff 
</task> 

<task id="1"> 
some other stuff 
</task> 
  1. 我怎樣才能得到所有打開和關閉標籤之間的文本?我試過awk和sed但沒有成功。
  2. 根據<task>標籤的數量,我可以創建多個字符串嗎?我的意思是,當我開始使用id =「0」時,它是否會以正確的</task>標記或文件中的最後一個結束?
+1

是這樣的文件還是有更多的XML?如果就這樣,你可以做'awk'/^/{flag = 0} flag'' – dawg

+0

@dawg你應該寫這個答案 - 它比我想出的要簡潔得多。 –

+0

@JerryJeremiah:你可以將它添加到你的,我將它投票;-) – dawg

回答

0

這可以通過許多方式完成。我認爲最簡單的方法是awk。把這個稱爲task.awk文件:

BEGIN{x=0;} 
/^<\/task>/{x=0;} 
{if(x==1)print $0;} 
/^<task [^>]*>/{x=1;} 

然後,如果你的XML是task.xml您可以:

awk -f task.awk < task.xml 

工作原理:

  1. 在開始的時候將該標誌設置爲false。
  2. 然後先檢查,看看我們是否應該關閉它,因爲它是一個接近標籤
    • 這樣做首先可以防止關閉標籤從印刷
  3. 然後只打印行,如果該標誌是
  4. 最後檢查,看看我們是否應該打開它,因爲它是一個開放的標籤
    • 這樣做最後的防止開放標籤從印刷
+1

你可以將{if(x == 1 )打印$ 0;}'用'x;' – karakfa

1

在GNU sed的:

sed -n '/<task id=/{n;:a;p;n;/<\/task>/!ba;s/.*/---/p;}' filename 

將輸出:

some stuff 
--- 
some other stuff 
--- 

這將搜索每個<task id=上的文件和迭代,直到下一個</task>s/.*/---/p;部分將結束標記轉換爲分隔符,您可以將其刪除並獲取所有字符串連接。

2

我建議對處理XML內容使用線定向工具,如grep/sed/awk等XML是一個面向行的格式;因此,在文本表達時,xml元素跨行的特定分佈是偶然的。 (你可以有你的例子寫在一個單行和它仍然將是同樣正確的XML格式。)

我解析以及形成在shell腳本 XML內容是xmlstarlet工具的建議。這是一種以腳本方式處理xml的瑞士軍刀。

首先,確保你的xml內容是well formed。以下是包含您例的數據形成的阱的xml:(該「井構性」一個XML文件的可與xmlstarlet val進行檢查)

<?xml version="1.0" encoding="UTF-8"?> 
<tasks> 
<task id="0">some stuff</task> 
<task id="1">some other stuff</task> 
<task id="2">yet another stuff</task> 
</tasks> 

爲了從XML,使用提取內容xmlstarlet sel。該工具需要使用XPath表達式來過濾必須選擇的內容。 (在很多方面,xmlstarlet sel和XPath是XML什麼grep和正則表達式爲面向行的內容。)使用保存在文件tasks.xml上面的XML樣本

例子:所有任務

提取物含量

$ xmlstarlet sel -T -t -m '/tasks/task' -v '.' -n tasks.xml 
some stuff 
some other stuff 
yet another stuff 

獲取所有任務ID

$ xmlstarlet sel -T -t -m '/tasks/task' -v '@id' -n tasks.xml 
0 
1 
2 
任務

提取內容的id爲大於或等於1

$ xmlstarlet sel -T -t -m '/tasks/task[@id>="1"]' -v '.' -n tasks.xml 
some other stuff 
yet another stuff 

天真轉換爲CVS格式

所有任務0

$ xmlstarlet sel -T -t -m '/tasks/task[@id="0"]' -v '.' -n tasks.xml 
some stuff 

提取物含量

$ xmlstarlet sel -T -t -m '/tasks/task' -v '@id' -o ',' -v '.' -n tasks.xml 0,some stuff 1,some other stuff 2,yet another stuff 
0

給出該文件作爲源在/tmp/data.xml

<task id="0"> 
some1 stuff for id 0 
some2 stuff for id 0 
</task> 

<task id="1"> 
some1 stuff for id 1 
some2 stuff for id 1 
</task> 

此代碼:

awk ' 
/<task id=/{tag_data=$0} 
/<\/task>/{tag_data=tag_data $0 " "; print tag_data} 
{tag_data=tag_data $0 " "}' < /tmp/data 

產生所需的結果:

<task id="0"><task id="0"> some1 stuff for id 0 some2 stuff for id 0 </task> 
<task id="1"><task id="1"> some1 stuff for id 1 some2 stuff for id 1 </task> 

它具有下列功能: 它搜索第一開口標記,並開始在變量tag_data中累積數據,直到它變爲closinig標記。在結束標籤處,您可以在tag_data變量的開始標籤和結束標籤之間獲得所有需要的數據。您可以輕鬆修改代碼以不存儲標籤,甚至可以將標識解析並存儲在單獨的變量中。

1

我做了HTML/XML pattern matcher這樣的事情。

例如,對於第一個任務,你可以這樣做:

$ xidel /tmp/xxx.xml -e '<task id="0">{.}</task>' 
some stuff 

或所有任務:

$ xidel /tmp/xxx.xml -e '<task>{.}</task>+' 
some stuff 
some other stuff 

雖然你的情況只有一個單一的元素,它是簡單的使用XPath:

獲得第一個任務:

$ xidel /tmp/xxx.xml -e //task[@id=0] 
some stuff 

獲取所有任務內容:

$ xidel /tmp/xxx.xml -e //task 
some stuff 
some other stuff 
相關問題