Trying to use <!ENTITY in ANDROID resources with error: "The entity was referenced, but not declared."

Trying to use <!ENTITY in ANDROID resources with error: "The entity was referenced, but not declared."

我正在按照此解决方案在我的字符串资源文件中使用实体:

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>

但是我得到这个错误:

The entity "ent_devicename" was referenced, but not declared.

如您所见Android Studio 识别外部实体文件:

和实体:

有人可以提供完整的正确示例来使事情正常进行吗? 我的意思是一个完全可编译的 Android Studio 项目,实体声明在一个单独的文件中。

更新 好的,如果你多关注一下这个w3schools link:

你看到了解决方案:

外部 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 似乎忽略了实体值(使用空字符串)。所以问题没有解决!

告诉我!

恐怕无法导入外部实体 (,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>

这个问题有 answers/comments 的历史,但对您没有帮助,所以让我们简化并一次解决一个问题。请使用我在下面显示的更新后的实体名称,并请为 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>

请在评论中明确告诉我您是否能够执行第 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 放在同一目录中。 (一旦您建立了预期的功能,这可以在以后放宽。)

再次,请在评论中告诉我您是否能够使第 2 步正常工作。

TL;DR 此功能已从 Android Studio 中删除。 请参阅错误报告 here

看起来 XML 外部实体在 Android Studio 上一度受支持。在我看来,Android Studio 目前应该支持外部实体,因为编辑器没有抱怨 XML 的底层处理实际上并没有像预期的那样包含 "referenced but not declared" 错误。

尽管我没有找到对 Android Studio 放弃外部实体 的明确引用,但由于发现了一个漏洞,它是有道理的。参见 Android Developers Susceptible to Data Exposure from XXE Attack and the security write-up

也有可能现在以某种方式限制了对外部实体的访问,但我认为如果是这种情况,Android Studio 会更有帮助。更有可能的是,由于存在漏洞,该功能刚刚被删除。

顺便说一句,我已经尝试过其他答案,但我没有运气 - 只是同样的错误。

编辑:

我刚看到一个 Medium post,其中讨论了 JetBrains 解决 XXE 漏洞的问题。

第二次编辑

我在错误跟踪器上找到了一个 reference 禁用功能。

this may have been disabled for security reason, it requires complete analysis before resolution, punting to 3.2

This was indeed disabled for security reasons (preventing XXE attacks) in Change-Id: I2f1978bc5458ba2b2b2d6ffbc9df5710c487a4e4.

它的状态是 "won't fix-intended behavior." 如果将 Studio 更改为发出一条错误消息,指出该设施出于安全原因被禁用,那就太好了。

或者,如果您仍然希望避免在 Java/Kotlin 上解析占位符,而是在 XML 文件中解析它们,那么您可以使用我创建的这个小库:https://github.com/LikeTheSalad/android-stem将允许你做这样的事情:

<resources>
    <string name="devicename">MyDeviceName</string>
    <string name="name">The name is ${devicename}</string>
</resources>

然后,您 make/build 项目,将生成一个新文件:

<!-- Auto generated during compilation -->
<resources>
    <string name="name">The name is MyDeviceName</string>
</resources>

有关上面提供的存储库的更多信息。