多模块 Java/Maven 项目中 DBUnit 的 XML DTD 路径?

发布于 2024-09-05 00:06:39 字数 573 浏览 10 评论 0原文

我有一个多模块 Maven 项目。在 persist 模块中,我有许多引用 DTD 的 XML 文件数据文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE myapp-data SYSTEM "myapp-data.dtd" >

<dataset>
      .....omitted for brevity....
</dataset>

DTD 与 XML 文件存储在同一目录中,甚至 Eclipse 也会报告这些 XML 文件有效。

但是,当我运行该应用程序时,DBUnit FlatXMLDataSet 会引发 FileNotFound 异常,因为它无法找到 DTD。它显然是在根项目目录(例如 myproject/)中寻找 DTD。我希望它在与 XML 文件本身相同的目录中查找 DTD(例如 myproject/persist/target/test-data)。

查看 DBUnit 源代码,它有这样的说法:“相对 DOCTYPE uri 是从当前工作字典解析的。”

有什么好方法来解决这个问题?

I have a multi-module maven project. Within the persist module I have a number of XML files data files that reference a DTD:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE myapp-data SYSTEM "myapp-data.dtd" >

<dataset>
      .....omitted for brevity....
</dataset>

The DTD is stored in the same directory with the XML files and even Eclipse reports these XML files as valid.

However, when I run the application, the DBUnit FlatXMLDataSet throws a FileNotFound exception because it cannot located the DTD. It is apparently looking for the DTD in the root project directory (e.g. myproject/). I would have expected it to look for the DTD in the same directory as the XML file itself (e.g. myproject/persist/target/test-data).

Looking at the DBUnit source code, it has this to say about it "Relative DOCTYPE uri are resolved from the current working dicrectory."

What's a good way to fix this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

浅黛梨妆こ 2024-09-12 00:06:39

好吧,我想我已经弄清楚了这一点。感谢上帝的开源。

FlatXmlDataSetBuilder 上有一个方法可以将流传送到 DTD。在我看来,这是一个公共方法,这很疯狂,但话又说回来,DBUnit 没有在与 dtd 文件的 XML 相同的目录中查找,这也很疯狂。现在,

String dtdResourceName = "classpath:test-data/myapp-data.dtd";      
Resource res = applicationContext.getResource(dtdResourceName);
builder.setMetaDataSetFromDtd(res.getInputStream());

我将 DOCTYPE 声明和 dtd 保留在与 XML 相同的目录中,并使用此 hack 来欺骗 DBUnit 做正确的事情。

OK, I think I figured this one out. Thank goodness for open source.

There is a method on FlatXmlDataSetBuilder that takes a stream to the DTD. It's crazy that this is a public method IMO, but then again, its crazy that DBUnit doesn't look in the same directory as the XML for the dtd file. So here it is:

String dtdResourceName = "classpath:test-data/myapp-data.dtd";      
Resource res = applicationContext.getResource(dtdResourceName);
builder.setMetaDataSetFromDtd(res.getInputStream());

Now I leave the DOCTYPE declaration with the dtd in the same directory as the XML and use this hack to fool DBUnit into doing the Right Thing.

东风软 2024-09-12 00:06:39

始终使用正确的变量来访问特殊目录,因为多模块构建具有与本地构建不同的工作目录:

因此,

  • 不要使用 mydir 使用 ${project.basedir}/mydir
  • 而不是 target/mydir 使用 ${project.build.directory}/mydir
  • 而不是 target/classes/mydir 使用 $ {project.build.outputDirectory}/mydir

这些变量始终评估当前项目,无论从何处调用。这是POM 变量概述(不完整,但最重要的内容都在其中) )

此外,如果您想做一些交互式查询式调试,help:evaluate mojo 派上用场:

只需调用

mvn help:evaluate

,系统就会提示您输入表达式。如果您输入表达式,例如 ${project.build.plugins[0]} ,则将列出指定元素的合并 dom


编辑:

好的,现在我想我看到了问题。那么为什么不直接引用 xml 中的目录:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE myapp-data SYSTEM "target/test-classes/myapp-data.dtd" >

我知道它不太漂亮,但它应该可以工作,无论是否是多模块。单元测试的当前目录始终是当前的 ${project.basedir},而不是父项目目录。

Always use the correct variables to access special directories, because multi-module builds have a different working directory than local builds:

So

  • instead of mydir use ${project.basedir}/mydir
  • instead of target/mydir use ${project.build.directory}/mydir
  • instead of target/classes/mydir use ${project.build.outputDirectory}/mydir

These variables always evaluate to the current project, no matter where it is called from. Here is an Overview of POM variables (not complete but the most important stuff is in there)

Also, if you ever want to do some interactive query-style debugging, the help:evaluate mojo comes in handy:

just call

mvn help:evaluate

and you will be prompted for an expression. If you enter an expression e.g. ${project.build.plugins[0]} , the merged dom for the specified element will be listed


EDIT:

ok, now I think I see the problem. then why not just reference the directory in the xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE myapp-data SYSTEM "target/test-classes/myapp-data.dtd" >

I know it's not pretty, but it should work, multi-module or not. the current directory for unit tests is always the current ${project.basedir}, not the parent project dir.

慕巷 2024-09-12 00:06:39

您可以将 DTD 发布到 Web 服务器,然后将其 HTTP URL 放入 DOCTYPE,例如:

<!DOCTYPE myapp-data SYSTEM "-//The Owner//The Description//EN" "http://host/path/to/myapp-data.dtd">

You could publish the DTD to a web server and then put its HTTP URL into the DOCTYPE, e.g.:

<!DOCTYPE myapp-data SYSTEM "-//The Owner//The Description//EN" "http://host/path/to/myapp-data.dtd">
千秋岁 2024-09-12 00:06:39

打开 XML 文件时尝试使用“File”而不是“FileInputStream”。

例如:

ReplacementDataSet dataSet = new ReplacementDataSet(new FlatXmlDataSet(new File(fileName)));

这样,DTD 的相对路径应该从 XML 文件的目录开始。

如果使用

ReplacementDataSet dataSet = new ReplacementDataSet(new FlatXmlDataSet(new FileInputStream(fileName)));

路径应该相对于当前工作目录。

Try using "File" instead of "FileInputStream" when opening an XML file.

For example:

ReplacementDataSet dataSet = new ReplacementDataSet(new FlatXmlDataSet(new File(fileName)));

This way, relative path to DTD should start with directory of the XML file.

And if you use

ReplacementDataSet dataSet = new ReplacementDataSet(new FlatXmlDataSet(new FileInputStream(fileName)));

path should be relative to current working directory.

很酷又爱笑 2024-09-12 00:06:39

它涉及一些丑陋的重复,但您可以将 DTD 的内容粘贴到相关 XML 文件中,然后将它们用作 内部 DTD

It involves some ugly duplication, but you could paste the contents of the DTD into the XML file(s) in question and then use them as internal DTDs.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文