2012-05-27 73 views
6

當我嘗試讀取與DTD的XML文檔(鷹文件),我得到的錯誤:C++ Builder的XE2,TXMLDocument的 'DTD禁止'

Project xx raised exception class EDOMParserError with message 'DTD is prohibited'

XML標頭看起來是這樣的:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE eagle SYSTEM "eagle.dtd"> 

如果我刪除第二行...

<!DOCTYPE eagle SYSTEM "eagle.dtd"> 

...一切工作正常。

經過一些Google搜索之後,似乎MSXML解析器默認有一個名爲'prohibitDTD'的選項設置爲true(在早期版本中它是錯誤的)。

但是,似乎不可能從TXMLDocument類將此選項設置爲false。一種解決方案似乎是重新編譯.pas庫或使用CoCreateInstance()自行創建接口。

我在Delphi中看到的所有例子都有,我很難將這些例子轉換爲C++ Builder。

有誰知道如何用C++ Builder XE2讀取DTD XML文檔?

我的示例代碼...

#include <xmldoc.hpp> 

_di_IXMLNode XMLObject; 

TXMLDocument *XMLDocument = new TXMLDocument(this); 
XMLDocument->LoadFromFile(fileName); // <----- Exception EDOMParserError 
XMLObject = XMLDocument->DocumentElement; 

謝謝...

回答

5

XE2引入了一個本地解決方案來解決這個問題:在Xml.Win.msxmldom.hpp中聲明瞭全局變量boolMSXML6_ProhibitDTD。您可以加載數據前將其設置爲falseTXMLDocument

#include <xmldoc.hpp> 
#include <msxmldom.hpp> 

MSXML6_ProhibitDTD = false; 
TXMLDocument *XMLDocument = new TXMLDocument(this): 
XMLDocument->LoadFromFile(fileName); 
_di_IXMLNode XMLObject = XMLDocument->DocumentElement; 

在一個側面說明:一般不產生TXMLDocument實例動態像這樣的好主意。這是更好地使用IXMLDocument接口來代替:

#include <xmldoc.hpp> 
#include <msxmldom.hpp> 

MSXML6_ProhibitDTD = false; 
_di_IXMLDocument XMLDocument = LoadXMLDocument(fileName); 
_di_IXMLNode XMLObject = XMLDocument->DocumentElement; 
+0

謝謝你的作品就像一個魅力!奇怪的是,這條信息應該很難找到......爲什麼IXMLDocument比TXMLDocument更好?據我所知,IXMLDocument是TXMLDocument的一部分。 –

+0

'TXMLDocument'實現了'IXMLDocument'接口,所以它具有相同的功能。但是,如果您使用「NULL」所有者動態實例化「TXMLDocument」(在創建短暫的XML對象時應該這樣做),它將充當引用計數對象。這是記錄的行爲。除非指定了Owner,否則將「TXMLDocument」的動態實例分配給「TXMLDocument」變量是不安全的。否則,您必須將其分配給'_di_IXMLDocument'變量,而不是正確維護引用計數。 –

+0

謝謝你的解釋。在我的情況下,TXMLDocument *的動態實例總是擁有一個擁有者並且貫穿整個應用程序。我有早期的項目代碼與TXMLDocument一起工作,所以我使用它來方便重用舊代碼。 –

0

您需要MSXMLDOM.pas複製到項目文件夾中,並對其進行修改,以解決此問題。

function TMSDOMDocument.GetMSDocument的實現更改爲以下內容,然後重新生成項目。

請注意,您必須使用IXMLDOMDocument2.setProperty而不是直接訪問ProhibitDTD,因爲IXMLDOMDocument2不會發布ProhibitDTD

function TMSDOMDocument.GetMSDocument: IXMLDOMDocument; 
var 
    Doc2: IXMLDOMDocument2; 
begin 
    Result := MSNode as IXMLDOMDocument; 
    if Supports(Result, IXMLDOMDocument2, Doc2) then 
     Doc2.setProperty('ProhibitDTD', False); 
end; 

需要注意的是,如果你不建築與運行的軟件包,這隻會工作!

該解決方案來自TeamB成員的Embarcadero論壇帖子;我記得閱讀過它,並通過CodeNewsFast在這些論壇中發現它 - EMBT論壇的搜索功能從未運行良好,而最近的重建或重新索引或其他因素使它變得比以前更糟。 :-)

+0

我是誰討論了TeamB成員這是EMBT論壇的解決方法。此解決方法僅在XE和更早版本中需要。 XE2爲這個確切的問題引入了一個本地解決方案。看到我的答案。 –

+0

是的@Remy。我知道。這就是爲什麼我發佈了我從中獲得的搜索鏈接;所以人們會知道我沒有拿出解決方案的功勞。 :-) –

1

由於與全局變量MSXML6_ProhibitDTD的解決方法已被棄用,我無法得到它與XE5任何工作,這裏是另一種解決方案:

由於在documentation說,有這種方法來改變DOM屬性

Xml.Win.Msxmldom.MSXMLDOMDocumentFactory.AddDOMProperty 

可惜這不是那麼微不足道使用此...

包括用於此命名空間頭:

#include <Xml.Win.msxmldom.hpp> 

Foo::Foo() 
{ 
    //change the dom property in your constructor. 
    ((TMSXMLDOMDocumentFactory*)Xml::Win::Msxmldom::MSXMLDOMDocumentFactory)->AddDOMProperty("ProhibitDTD", False, true); 
} 

和訪問此方法。 (演員陣容是必要的,因爲MSXMLDOMDocumentFactory本身由元類接口繼承或者所以不得到背後的理念。)

從德爾福博客的啓發:https://bobsotherblog.wordpress.com/2013/09/19/fixing-dtd-is-prohibited-error-in-delphi/