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

4

23

I'm following this solution to use enetities in my string resource file:

Is it possible to do string substitution in Android resource XML files directly?

I'm using an external file in the resource tree: /res/raw/entities.dtd, its content:

<!ENTITY ent_devicename "MyDeviceName">

In the string.xml resource file:

<!DOCTYPE resources [
    <!ENTITY % ent_devicename SYSTEM "../raw/entities.dtd">
    %ent_devicename;
]>

<resources>
    <string name="name">The name is &ent_devicename;</string>
</resources>

but I get this error:

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

As you can see Android Studio recognizes the external entity file:

enter image description here

and the entity:

enter image description here

Can someone provide full a correct example to make things work? I mean a full compilable Android Studio project, with entities declarations in a separated file.

UPDATE Ok, if you pay more attention to this w3schools link:

https://www.w3schools.com/xml/xml_dtd_entities.asp

you see the solution:

the external entities.dtd files contains

<!ENTITY ent_devicename "MyDeviceName">

then the new string resource resource:

<?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>

I changed <!ENTITY % ent_devicename to <!ENTITY ent_devicename (no more %) I deleted %ent_devicename;

Now it compiles but the resulting APK seems to ignore the entity values (uses an empty string). So the problem is not resolved!

Let me know!

Chiquita answered 19/6, 2018 at 17:32 Comment(5)
@VicJordan The two XML files needed (strings.xml and entities.dtd) are already posted in the question. There are no other relevant files.Fourlegged
Using the same name for the external parameter entity %ent_devicename; as for the internal entity &ent_devicename; is asking for trouble. Change one or the other (consistently in definition and use) and see if your problem doesn't go away.Hindmost
@Hindmost I renamed the entity name in the external file <!ENTITY ent_devicename_2 "MyDeviceName"> but the problems is still here.Fourlegged
@Hindmost I pudate the question with some tricks, now it compiles but the resulting strings resources has empty entity value.Fourlegged
Your update would read in the contents of ../raw/entities.dtd literally and place them where you reference &ent_devicename; -- not likely what you want. See my answer below for more detailed help. Thanks.Hindmost
I
21

TL;DR This feature has been removed from Android Studio. See the bug report here.

It looks like XML External Entities were supported at one time in Android Studio. It also looks to me like Android Studio currently should be supporting external entities since the editor doesn't complain. The underlying processing of the XML doesn't actually do the inclusion as expected giving the "referenced but not declared" error.

Although I have not found an explicit reference to Android Studio abandoning external entities, it would make sense due to a vulnerability that was uncovered. See Android Developers Susceptible to Data Exposure from XXE Attack and the security write-up.

It is also possible that access to external entities are now gated somehow, but I think that Android Studio would be more helpful if that is the case. It is more likely that the functionality was just removed due to the vulnerability.

By the way, I have experimented with the other answers and I have had no luck - just the same error.

Edit:

I just came across a Medium post that discusses JetBrains addressing the XXE vulnerability.

Second edit

I found a reference for the disablement on the bug tracker.

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

and

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

It's status is "won't fix-intended behavior." It would have been nice if Studio had been changed to emit an error message that the facility was disabled for security reasons.

Intermarry answered 13/7, 2018 at 18:25 Comment(1)
Your answer is the best for now, so I upvoted it. Thanks for all information you've collected. So... no more external entities. What a pity!Fourlegged
H
2

There's a history of answers/comments to this question not helping you, so let's simplify and approach one step at a time. Please use the updated entity names I show below, and please use a single directory for both the XML file and the included entities file.

1. Establish that internal entity references are working.

string.xml

<!DOCTYPE resources [
  <!ENTITY devicename "MyDeviceName">
]>

<resources>
    <string name="name">The name is &devicename;</string>
</resources>

Verify that this works as expected: After applications parse this XML file, it should be equivalent to this XML file:

<resources>
    <string name="name">The name is MyDeviceName</string>
</resources>

Let me know explicitly in the comments whether you are able to get step 1 working.

2. Add the extra level of indirection, if needed.

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>

To an XML application that uses a conforming XML parser, string.xml will again be equivalent to

<resources>
    <string name="name">The name is MyDeviceName</string>
</resources>

and you will now be able to share the entities defined in entities.ent.

For this step I ask that you take care not to re-use the entity names for the internal and external entities and that you not add any complications due to different directory location; place both entities.ent and string.xml in the same directory. (This can be relaxed later once you establish the expected functionality.)

Again, let me know in the comments whether you are able to get step 2 working.

Hindmost answered 12/7, 2018 at 16:3 Comment(7)
No, this solution does not work. I don't want the entities file in the same folder as the string resource, becouse I'm trying to get benefits from the Gradle variants mechanism and I need to keep the files in a separate folder (and it's working good). First step is working, but for the second one, Android Studio says that "Unresolved Entity Reference".Fourlegged
Glad to hear that you've gotten step #1 to work. Next, for debugging purposes, as a temporary measure, could you establish that step #2 works when entities.ent is in the same directory as string.xml and where the exact files and entity names shown in step #2 are used?Hindmost
Android Studio allows to put that file in the same folder, but when I compile (Gradle) I get an error because it is a special folder and I can't put a .dtd file in it. Anyway If i put the file in the same folder the problem is still here: "Unresolved Entity Reference"Fourlegged
We cannot help you debug an arbitrary and unspecified build process. Know that if you are able to wrestle your build process into submission such that entities.ent and string.xml are in the same directory when string.xml is parsed, the files given in step #2 will work together. As a next step, you can try using an absolute rather than relative reference for entities.ent to relax the requirement that the files have to be in the same directory. See XML Catalogs for further flexibility in file placement. This is all the more I can help you from this vantage point. Good luck.Hindmost
I'll try to use an absolute path. Thank you for your help.Fourlegged
@Chiquita I'm having the exact same problem. Trying to use one of both flavor/res/raw/entities/entities.ent entity declarations for the same main/res/values/strings.xml file.I'm being shown the "reference, but not declared" error. Using an absolute path defeats the purpose of the flavor. I'm thinking that maybe an internal entity reference that is modified via the build.gradle script might fix this?Rothermere
@Rothermere external entities don't work anymore have a look around this pageFourlegged
A
1

I am afraid importing external entities is not possible (proof1,proof2). Here is the only way.

<?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>
Acanthocephalan answered 26/6, 2018 at 11:7 Comment(3)
Ok, but we are not talking about browsers... If Android Studio recognizes external references in the correct way I expect the same for the gradle compiler. Your response is not wat I expected.Fourlegged
@Seraphim's, he is right, and I think, his answer is similar to accepted.Brachyuran
Hi, did you tried in the last version of Android Studio?Fourlegged
A
0

Alternatively, if you still prefer avoiding resolving placeholders on Java/Kotlin and rather get them resolved in the XML files, then you could use this small library I created: https://github.com/LikeTheSalad/android-stem which will allow you to do something like this:

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

And then, you make/build the project, and a new file will be generated with:

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

More info on the repo provided above.

Animalize answered 18/11, 2019 at 17:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.