尝试在 ANDROID 资源中使用 <!ENTITY 时出现错误:“实体已被引用,但未声明。”
Posted
技术标签:
【中文标题】尝试在 ANDROID 资源中使用 <!ENTITY 时出现错误:“实体已被引用,但未声明。”【英文标题】:Trying to use <!ENTITY in ANDROID resources with error: "The entity was referenced, but not declared." 【发布时间】:2018-11-28 17:55:31 【问题描述】:我正在按照这个解决方案在我的字符串资源文件中使用 enetities:
Is it possible to do string substitution in android resource XML files directly?
我在资源树中使用了一个外部文件:/res/raw/entities.dtd
,它的内容:
<!ENTITY ent_devicename "MyDeviceName">
在string.xml
资源文件中:
<!DOCTYPE resources [
<!ENTITY % ent_devicename SYSTEM "../raw/entities.dtd">
%ent_devicename;
]>
<resources>
<string name="name">The name is &ent_devicename;</string>
</resources>
但我收到此错误:
实体“ent_devicename”已被引用,但未声明。
如您所见,Android Studio 可以识别外部实体文件:
和实体:
有人可以提供完整的正确示例来使事情正常进行吗? 我的意思是一个完全可编译的 Android Studio 项目,实体声明在一个单独的文件中。
更新 好的,如果你多关注这个 w3schools 链接:
https://www.w3schools.com/xml/xml_dtd_entities.asp
你看到了解决方案:
外部entities.dtd
文件包含
<!ENTITY ent_devicename "MyDeviceName">
然后是新的字符串资源资源:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE resources [
<!ENTITY ent_devicename SYSTEM "../raw/entities.dtd">
]>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="Typos">
<string name="ent_devicenamxxe2">&ent_devicename;</string>
我将 <!ENTITY % ent_devicename
更改为 <!ENTITY ent_devicename
(不再有 %)
我删除了%ent_devicename;
现在它可以编译,但生成的 APK 似乎忽略了实体值(使用空字符串)。所以问题没有解决!
告诉我!
【问题讨论】:
@VicJordan 所需的两个 XML 文件(strings.xml 和entities.dtd)已发布在问题中。没有其他相关文件。 对外部参数实体%ent_devicename;
和内部实体&ent_devicename;
使用相同的名称是自找麻烦。改变一个或另一个(在定义和使用上保持一致),看看你的问题是否不会消失。
@kjhughes 我重命名了外部文件中的实体名称 但问题仍然存在。
@kjhughes 我用一些技巧来解决这个问题,现在它可以编译,但生成的字符串资源具有空实体值。
您的更新会从字面上读取../raw/entities.dtd
的内容并将它们放在您引用&ent_devicename;
的位置——这可能不是您想要的。有关更详细的帮助,请参阅my answer below。谢谢。
【参考方案1】:
TL;DR 此功能已从 Android Studio 中删除。请参阅错误报告 here。
Android Studio 似乎曾一度支持 XML 外部实体。在我看来,Android Studio 目前应该支持外部实体,因为编辑器没有抱怨 XML 的底层处理实际上并没有按预期进行包含,给出了“引用但未声明”错误。
虽然我没有找到关于 Android Studio 放弃外部实体的明确引用,但由于发现了一个漏洞,这将是有意义的。请参阅Android Developers Susceptible to Data Exposure from XXE Attack 和security write-up。
现在也有可能以某种方式限制对外部实体的访问,但我认为如果是这种情况,Android Studio 会更有帮助。更有可能是由于该漏洞而刚刚删除了该功能。
顺便说一句,我已经尝试过其他答案,但我没有运气 - 只是同样的错误。
编辑:
我刚刚遇到了一个 Medium post,它讨论了 JetBrains 解决 XXE 漏洞的问题。
第二次修改
我在错误跟踪器上找到了一个 reference 禁用。
出于安全原因,这可能已被禁用,需要在解决之前进行完整分析,将其踢到 3.2
和
出于安全原因(防止 XXE 攻击),这确实在 Change-Id: I2f1978bc5458ba2b2b2d6ffbc9df5710c487a4e4 中被禁用。
它的状态是“不会修复预期的行为”。如果 Studio 已更改为发出一条错误消息,指出该工具出于安全原因已被禁用,那就太好了。
【讨论】:
你的答案是目前最好的,所以我投了赞成票。感谢您收集的所有信息。所以......没有更多的外部实体。太可惜了!【参考方案2】:这个问题的答案/cmets 的历史对您没有帮助,所以让我们简化并一步一步地解决。请使用我在下面显示的更新后的实体名称,并且请为 XML 文件和包含的实体文件使用一个目录。
1。确定内部实体引用是否正常工作。
string.xml
<!DOCTYPE resources [
<!ENTITY devicename "MyDeviceName">
]>
<resources>
<string name="name">The name is &devicename;</string>
</resources>
验证这是否按预期工作:应用程序解析此 XML 文件后,它应该等同于此 XML 文件:
<resources>
<string name="name">The name is MyDeviceName</string>
</resources>
在 cmets 中明确告诉我您是否能够使第 1 步正常工作。
2。如果需要,添加额外的间接级别。
entities.ent
<!ENTITY devicename "MyDeviceName">
string.xml
<!DOCTYPE resources [
<!ENTITY % ext_entities SYSTEM "entities.ent">
%ext_entities;
]>
<resources>
<string name="name">The name is &devicename;</string>
</resources>
对于使用符合标准的 XML 解析器的 XML 应用程序,string.xml 将再次等同于
<resources>
<string name="name">The name is MyDeviceName</string>
</resources>
您现在可以共享 entities.ent 中定义的实体。
对于这一步,我要求您注意不要为内部和外部实体重复使用实体名称,并且不要因目录位置不同而增加任何复杂性;将entities.ent 和string.xml 放在同一个目录中。 (一旦你建立了预期的功能,这可以放宽。)
再次,在 cmets 中让我知道您是否能够使第 2 步正常工作。
【讨论】:
不,此解决方案不起作用。我不希望实体文件与字符串资源位于同一文件夹中,因为我正在尝试从 Gradle 变体机制中受益,并且我需要将文件保存在单独的文件夹中(并且它运行良好)。第一步正在工作,但对于第二步,Android Studio 说“未解析的实体引用”。 很高兴听到您已经完成了第一步。接下来,出于调试目的,作为一种临时措施,您能否确定步骤#2 在 entities.ent 与 string.xml 位于同一目录中时有效,并且确切的位置在哪里?使用步骤 #2 中显示的文件和实体名称? Android Studio 允许将该文件放在同一个文件夹中,但是当我编译 (Gradle) 时出现错误,因为它是一个特殊文件夹,我无法将 .dtd 文件放入其中。无论如何,如果我将文件放在同一个文件夹中,问题仍然存在:“未解决的实体参考” 我们无法帮助您调试任意且未指定的构建过程。要知道,如果您能够将构建过程争取到提交,以便 entities.ent 和 string.xml 在 string.xml 时位于同一目录中b> 被解析,步骤 #2 中给出的文件将一起工作。下一步,您可以尝试对 entities.ent 使用绝对引用而不是相对引用,以放宽文件必须位于同一目录中的要求。有关文件放置的更多灵活性,请参阅 XML 目录。从这个有利的角度来看,我可以为您提供更多帮助。祝你好运。 @dekaru 外部实体不再起作用 看看这个页面【参考方案3】:恐怕无法导入外部实体(proof1,proof2)。这是唯一的方法。
<?xml version="1.0"?>
<!DOCTYPE resources [
<!ENTITY value_a "Value A">
<!ENTITY value_b "Value B">
]>
<resources>
<string name="app_name">&value_a;</string>
<string name="app_settings ">&value_b;</string>
</resources>
【讨论】:
好的,但我们不是在谈论浏览器...如果 Android Studio 以正确的方式识别外部引用,我希望 gradle 编译器也是如此。你的反应不是我所期望的。 @Seraphim's,他是对的,我认为,他的回答类似于接受。 您好,您在最新版本的 Android Studio 中尝试过吗?【参考方案4】:或者,如果您仍然希望避免在 Java/Kotlin 上解析占位符,而是在 XML 文件中解析它们,那么您可以使用我创建的这个小库:https://github.com/LikeTheSalad/android-string-reference,它允许您执行以下操作:
<resources>
<string name="devicename">MyDeviceName</string>
<string name="template_name">The name is $devicename</string>
</resources>
然后,您制作/构建项目,将生成一个新文件:
<resources>
<string name="name">The name is MyDeviceName</string>
</resources>
关于上面提供的 repo 的更多信息。
【讨论】:
以上是关于尝试在 ANDROID 资源中使用 <!ENTITY 时出现错误:“实体已被引用,但未声明。”的主要内容,如果未能解决你的问题,请参考以下文章
Xamarin Android 资源 NotFoundException ZXingNetMobile
android module里面的strings.xml怎么区分中英文
Android WebView从资源原始文件夹加载html文件
无法解析区域设置“en_US”的资源包“*”(Flex、Flash Builder)