2010-12-17 27 views
1

我們在unix上有多個xml文件。我們需要將它們轉換爲平面文件。我們使用C語言解析了一層xml文件(C被用作C可以與Teradata fastload進行通信,這是我們使用inmod的目標框,並且它會在其他語言中完成其他語言的其他語言分析,我們需要執行兩次解析一個用於轉換成平面文件,另一個用於加載ito teradata)。即下面的文件Unix XML文件轉換爲平面文件

<book id="bk101"> 
     <author>Gambardella, Matthew</author> 
     <title>XML Developer's Guide</title> 
     <genre>Computer</genre> 
     <price>44.95</price> 
    </book> 

轉換成

bk101~Gambardella, Matthew~XML Developer's Guide~Computer~44.95~ 

此,我們通過解析C中的文件,但看到XML文件的原始格式,低於後實現的。 (請不要將它視爲必需的文件,我只是在提供一個想法)

<book id="bk101"> 
     <author>Gambardella, Matthew</author> 
     <title>XML Developer's Guide</title> 
     <genre>Computer</genre> 
      <modified>2010-01-02</modified> 
      <modified>2010-01-03</modified> 
     <price>44.95</price> 
    </book> 

這應該轉換爲兩個記錄似乎。

bk101~Gambardella, Matthew~XML Developer's Guide~Computer~2010-01-02~44.95~ 
bk101~Gambardella, Matthew~XML Developer's Guide~Computer~2010-01-03~44.95~ 

但是現在我們覺得我們的C代碼對於這個需求來說會很複雜。所以我們正在研究可以在unix上輕鬆使用的其他選項。任何人都可以給我們unix的不同語言/選項的任何工作示例代碼?

回答

3

您可以使用XSLT。我使用可以在Unix上運行的Saxon(Java)。

這個樣式表可以處理你的XML樣本:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:template match="/book"> 
    <xsl:choose> 
     <xsl:when test="modified"> 
     <xsl:for-each select="modified"> 
      <xsl:call-template name="dump-line"> 
      <xsl:with-param name="pos" select="position()"/> 
      </xsl:call-template>   
     </xsl:for-each> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:value-of select="@id"/><xsl:text>~</xsl:text> 
     <xsl:value-of select="author"/><xsl:text>~</xsl:text> 
     <xsl:value-of select="title"/><xsl:text>~</xsl:text> 
     <xsl:value-of select="genre"/><xsl:text>~</xsl:text> 
     <xsl:value-of select="price"/> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 

    <xsl:template name="dump-line"> 
    <xsl:param name="pos"/> 
    <xsl:value-of select="/book/@id"/><xsl:text>~</xsl:text> 
    <xsl:value-of select="/book/author"/><xsl:text>~</xsl:text> 
    <xsl:value-of select="/book/title"/><xsl:text>~</xsl:text> 
    <xsl:value-of select="/book/genre"/><xsl:text>~</xsl:text> 
    <xsl:value-of select="/book/modified[$pos]"/><xsl:text>~</xsl:text> 
    <xsl:value-of select="/book/price"/> 
    <xsl:text>&#x0A;</xsl:text> 
    </xsl:template> 
</xsl:stylesheet> 

如果沒有modified元素,一個記錄被輸出。如果有modified元素,則會輸出與modified元素一樣多的記錄。

樣本輸出瓦特/修改內容:

bk101~Gambardella, Matthew~XML Developer's Guide~Computer~2010-01-02~44.95 
bk101~Gambardella, Matthew~XML Developer's Guide~Computer~2010-01-03~44.95 
+0

非常感謝。你提供了一個很好的工作例子。非常感謝。您的示例增加了我對學習XSLT的興趣。我使用xalan(c版本)來運行ur示例代碼,並且完美地工作。 Stackoverflow極客很棒。感謝所有人的幫助和建議。我會嘗試大部分可用選項,讓你知道最終產品。 – 2010-12-18 06:32:34

+0

非常感謝你。我能夠爲更復雜的xml文件創建簡單的xslt腳本,我使用多個循環。保持搖擺。因爲你現在我能夠想出使我的600行C代碼複雜化並開始學習新語言的想法。在我的組織使用xalan後,現在我必須在unix上嘗試相同的腳本和執行。 – 2010-12-18 07:41:35

+0

你非常歡迎。我很高興它有幫助。不過你應該看看撒克遜人。 HE版本仍然是免費的,並且支持XSLT 2.0。 http://saxon.sourceforge.net/ Xalan不支持2.0 – 2010-12-19 21:40:27

0

如何在格式化的行bk101~Gambardella, Matthew~XML Developer's Guide~Computer~2010-01-02,2010-01-03~44.95~。當然,必須特別注意修改字段可以包含值列表的事實。這就像你可以做到的一樣平坦。

+0

感謝您的答覆。那麼,最終它應該加載到數據庫表中。所以這個記錄應該被分成兩個記錄用於報告。我們正在思考perl xml解析器。任何機構都知道perl上的任何示例代碼都可以滿足上述要求? – 2010-12-17 13:32:34

+0

我敢打賭,如果你谷歌它有很多的例子。是否需要使用腳本?莫諾可以接受作爲一種工具嗎? .NET框架在解析和處理XML方面有很多好處,使它變得輕而易舉...... – 2010-12-17 19:29:52

1

如果要加載數據到數據庫中,並且您有共享許多與其他領域的一個關係,那麼你需要確保你的數據庫結構是達到標準的字段。即一本書的表格和一張修改日期的表格。否則,它看起來像有兩本書,實際上有兩本修改日期。

但是,如果要加載數據到數據庫中,你爲什麼首先將其轉換爲平面文件?你說你想避免兩次解析。那麼它看起來像你將有一個傳遞解析XML和輸出爲平面文件,另一個解析平面文件並將其輸入到數據庫中。爲什麼不簡單地解析XMl並將數據直接放入數據庫?

爲什麼有格式,如XML被髮明,一個是封裝在基於文本文件複雜的數據關係的原因。通過轉換爲「平面文件」,您將失去這種複雜性。如果你準備將數據導入一個可以處理這種複雜性並存儲這些關係的環境......爲什麼不保留它?

您的數據庫有一個API,或者可以將它只能導入純文本文件?

---編輯---

它更容易作爲一個答案的一部分,不是一系列的評論回覆。

首先,感謝您的澄清。第二,不,我不能提供示例代碼。主要是因爲你想要的聲音非常具體。 第三,我認爲你有兩種選擇:

1)你已經編寫了一段C代碼來解析XML。您必須考慮將其全部丟棄並將其重新寫入Perl並支持它的成本,以及改進它將數據直接導入Teradata數據庫以及之後維護它的成本的成本。

2)對於Perl來說,有很多XML解析器,根據我的經驗,他們使遍歷XML樹/數據結構比C更容易。我不是Perl的粉絲,但是我寫了代碼來處理用C語言準備好已解析的XML樹,我從來沒有恨過它。相比之下,使用Perl更簡單,甚至更快。

有大量的Perl模塊來解析XML。我建議你在網上搜索一些關於他們的評論,以決定哪一種最簡單或最適合你使用。

有一個名爲Teradata :: SQL的Perl模塊,它允許您將數據導入Teradata數據庫。可能有更簡單/更好使用的其他模塊。我沒有任何經驗,所以不能提出建議。搜索http://www.cpan.org可用於任何模塊。


最後,我強烈建議您確保花一些時間確保Teradata數據庫的設計與進入其中的數據匹配。正如我上面所說的,你顯然在修改日期和書籍之間有多對一的關係,所以這意味着你需要一個表格來修改日期和書籍表格,並且在你的表格設計中糾正多對一的關係。每行放入一個條目,導致只有修改日期不同的同一本書的多行是非常錯誤的。可能還有其他多對一的關係,比如作者。想象一下由作者A1和A2寫的書B,其修改日期爲M1和M2。如果您使用上面討論過的每種組合都有一行的方法,則最終會有同一本書的4個條目,看起來您有兩本書名相同但由不同作者撰寫的書。

花一些時間來確保您瞭解XML文件中數據的結構。這應該由DTD明確定義。

+0

對不起,有一個誤解...... Teradata inmod設施是一個共享對象(在Windows中的DLL,所以在Unix中)這可以通過fastload實用程序調用以獲取要加載到teradata中的記錄。所以在這裏,我目前只對xml文件進行一次傳遞。 Teradata對xml的支持較少,並且只有在不久的將來升級後才能支持的碎化選項。所以我們正在尋找其他的選擇,即使他們需要兩次通過。你能提供任何示例代碼在perl /其他可以轉換這種方式嗎?感謝您的答覆。 – 2010-12-17 14:00:52

+0

非常感謝您的意見和建議。 – 2010-12-18 06:11:59

1

XSLT是一個選項;檢查出xsltproc工具。或者,你也可以更簡單的XQuery,儘管你可能需要強制它生成文本。下面的XQuery腳本幾乎你想要做什麼(只列出了幾個字段):

for $book in doc("book.xml")/book 
for $mod in $book/modified 
return concat($book/@id, "~", $book/title, "~", $mod, " 
") 

您可以

java net.sf.saxon.Query '!method=text' script.xq 

爲Unix另一種流行的XQuery處理器XQilla通過Saxon運行這一點,雖然我我不確定它可以產生非XML輸出。

(有可能是對我產生一個新行的尷尬方式智能替代。)