2015-11-23 22 views
1

我正在使用帶有DOMDocument60分析器的Excel 2010/VBA/XML在Oracle中生成數據報告。我遇到空值問題。 Oracle在xsql查詢中支持null-indicator="yes"以確保返回的記錄集中包含空字段。如果一個字段有一個值,那麼XML看起來像這樣:<M_NOTCH>8</M_NOTCH>,如果它爲空,它看起來像這樣:<M_NOTCH NULL="TRUE"/>Excel XML導入創建空值爲NULL的額外列

我的代碼調用Web服務,使查詢:

Dim XML_HTTP As New MSXML2.XMLHTTP60: Call XML_HTTP.Open("POST", QUERY_URL, False): Call XML_HTTP.send 

,並檢索XML結果:

Dim XML_OUTPUT As DOMDocument60: Set XML_OUTPUT = XML_HTTP.responseXML 

它保存文件:

XML_OUTPUT.Save (FILE_PATH) 

,然後負載保存文件中的電子表格:

Call DestinationWorksheet.Parent.XmlImport(FILE_PATH, Nothing, True, DestinationWorksheet.Range("A1")) 

它使用XML數據填充Excel電子表格。

如果在<M_NOTCH NULL="TRUE"/>這樣的格式中存在空值,則Excel會認爲這是兩個字段,併爲M_NOTCH(此行沒有數據)創建一列,另一列爲NULL,值爲TRUE。

我已經嘗試過使用xsql設置null-indicator =「no」,這消除了NULL列,但它有一個不同的,不可接受的問題:動態構建的列順序,以便如果第一個XML記錄代表包含空字段的Oracle記錄將從XML中排除,並且只有在包含這些字段的記錄遇到時纔會添加到Excel列表列表中,在這種情況下,它們會添加到列列表的末尾。

我也試着用<M_NOTCH> </M_NOTCH>代替<M_NOTCH NULL="TRUE"/>,那很成功。

有誰知道如何讓Oracle使用語法<M_NOTCH> </M_NOTCH>或讓Excel識別<M_NOTCH NULL="TRUE"/>而不是創建額外的列?

+0

我傾向於將XSL轉換應用於刪除NULL att的Oracle響應完全排骨。在[這個答案](http://stackoverflow.com/a/3117549/2127508)中的做法將實現這一點 – barrowc

回答

1

考慮一個XSLT(爲最終用途需要重新構造XML文件的聲明性編程語言)來刪除@NULL屬性。 VBA可以使用帶有Microsoft XML對象的XSLT處理器。所需的XSLT非常簡單直接,您可以在其中包含標識轉換以便按原樣複製所有內容(節點和屬性),然後在@NULL上運行空模板匹配以刪除文檔中出現的任何屬性。

XSLT(下面嵌入的VBA字符串)

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:output version="1.0" encoding="UTF-8" indent="yes" /> 

    <!-- Identity transform --> 
    <xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="@NULL">  
    </xsl:template> 

</xsl:stylesheet> 

VBA(合併到您的項目作爲子程序或功能,甚至通過爲參數的Oracle XML文件路徑)

Sub TransformXML() 

    Dim xmlDoc As Object, xslDoc As Object, newDoc As Object 

    Set xmlDoc = CreateObject("MSXML2.DOMDocument") 
    Set xslDoc = CreateObject("MSXML2.DOMDocument") 
    Set newDoc = CreateObject("MSXML2.DOMDocument") 

    xmlDoc.Load "Original.xml" 
    xmlDoc.async = False    

    ' EMBEDDED XSLT ' 
    xslDoc.LoadXML "<?xml version=" & Chr(34) & "1.0" & Chr(34) & "?>" _ 
      & "<xsl:stylesheet version=" & Chr(34) & "1.0" & Chr(34) _ 
      & "    xmlns:xsl=" & Chr(34) & "http://www.w3.org/1999/XSL/Transform" & Chr(34) & ">" _ 
      & "<xsl:strip-space elements=" & Chr(34) & "*" & Chr(34) & " />" _ 
      & "<xsl:output method=" & Chr(34) & "xml" & Chr(34) & " indent=" & Chr(34) & "yes" & Chr(34) & "" _ 
      & "   encoding=" & Chr(34) & "UTF-8" & Chr(34) & "/>" _ 
      & " <xsl:template match=" & Chr(34) & "node() | @*" & Chr(34) & ">" _ 
      & " <xsl:copy>" _ 
      & " <xsl:apply-templates select=" & Chr(34) & "node() | @*" & Chr(34) & " />" _ 
      & " </xsl:copy>" _ 
      & " </xsl:template>" _ 
      & "<xsl:template match=" & Chr(34) & "@NULL" & Chr(34) & ">" _ 
      & "</xsl:template>" _ 
      & "</xsl:stylesheet>" 

    xslDoc.async = False 
    xmlDoc.transformNodeToObject xslDoc, newDoc 
    newDoc.Save "OutputXML.xml" ' READY FOR FINAL IMPORT '   

    MsgBox "Successfully transformed XML!", vbInformation 

    Set xmlDoc = Nothing 
    Set xslDoc = Nothing 
    Set newDoc = Nothing 

End Sub