Skip to content

Commit ad85ac5

Browse files
author
Peter
committed
fixing xml escaping problem, graphhopper#572
1 parent 4b93290 commit ad85ac5

File tree

2 files changed

+32
-14
lines changed

2 files changed

+32
-14
lines changed

core/src/main/java/com/graphhopper/util/InstructionList.java

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -179,28 +179,39 @@ public String createGPX( String trackName, long startTimeMillis )
179179
private void createWayPointBlock( StringBuilder output, Instruction instruction )
180180
{
181181
output.append("\n<wpt ");
182-
output.append("lat='").append(Helper.round6(instruction.getFirstLat()));
183-
output.append("' lon='").append(Helper.round6(instruction.getFirstLon())).append("'>");
182+
output.append("lat=\"").append(Helper.round6(instruction.getFirstLat()));
183+
output.append("\" lon=\"").append(Helper.round6(instruction.getFirstLon())).append("\">");
184+
String name;
184185
if (instruction.getName().isEmpty())
185-
output.append(" <name>").append(instruction.getTurnDescription(tr)).append("</name>");
186+
name = instruction.getTurnDescription(tr);
186187
else
187-
output.append(" <name>").append(instruction.getName()).append("</name>");
188+
name = instruction.getName();
189+
190+
output.append(" <name>").append(simpleXMLEscape(name)).append("</name>");
188191
output.append("</wpt>");
189192
}
190193

194+
static String simpleXMLEscape( String str )
195+
{
196+
// We could even use the 'more flexible' CDATA section but for now do the following. The 'and' could be important sometimes:
197+
return str.replaceAll("&", "&amp;").
198+
// but do not care for:
199+
replaceAll("[\\<\\>]", "_");
200+
}
201+
191202
public String createGPX( String trackName, long startTimeMillis, boolean includeElevation, boolean withRoute, boolean withTrack, boolean withWayPoints )
192203
{
193204
DateFormat formatter = Helper.createFormatter();
194-
195-
String header = "<?xml version='1.0' encoding='UTF-8' standalone='no' ?>"
196-
+ "<gpx xmlns='http://www.topografix.com/GPX/1/1' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'"
197-
+ " creator='Graphhopper version " + Constants.VERSION + "' version='1.1'"
205+
206+
String header = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>"
207+
+ "<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
208+
+ " creator=\"Graphhopper version " + Constants.VERSION + "\" version=\"1.1\""
198209
// This xmlns:gh acts only as ID, no valid URL necessary.
199210
// Use a separate namespace for custom extensions to make basecamp happy.
200-
+ " xmlns:gh='https://graphhopper.com/public/schema/gpx/1.1'>"
211+
+ " xmlns:gh=\"https://graphhopper.com/public/schema/gpx/1.1\">"
201212
+ "\n<metadata>"
202213
+ "<copyright author=\"OpenStreetMap contributors\"/>"
203-
+ "<link href='http://graphhopper.com'>"
214+
+ "<link href=\"http://graphhopper.com\">"
204215
+ "<text>GraphHopper GPX</text>"
205216
+ "</link>"
206217
+ "<time>" + formatter.format(startTimeMillis) + "</time>"
@@ -242,8 +253,8 @@ public String createGPX( String trackName, long startTimeMillis, boolean include
242253
gpxOutput.append("<trkseg>");
243254
for (GPXEntry entry : createGPXList())
244255
{
245-
gpxOutput.append("\n<trkpt lat='").append(Helper.round6(entry.getLat()));
246-
gpxOutput.append("' lon='").append(Helper.round6(entry.getLon())).append("'>");
256+
gpxOutput.append("\n<trkpt lat=\"").append(Helper.round6(entry.getLat()));
257+
gpxOutput.append("\" lon=\"").append(Helper.round6(entry.getLon())).append("\">");
247258
if (includeElevation)
248259
gpxOutput.append("<ele>").append(Helper.round2(entry.getEle())).append("</ele>");
249260
gpxOutput.append("<time>").append(formatter.format(startTimeMillis + entry.getTime())).append("</time>");
@@ -255,7 +266,7 @@ public String createGPX( String trackName, long startTimeMillis, boolean include
255266

256267
// we could now use 'wpt' for via points
257268
gpxOutput.append("\n</gpx>");
258-
return gpxOutput.toString().replaceAll("\\'", "\"");
269+
return gpxOutput.toString();
259270
}
260271

261272
public void createRteptBlock( StringBuilder output, Instruction instruction, Instruction nextI )
@@ -264,7 +275,7 @@ public void createRteptBlock( StringBuilder output, Instruction instruction, Ins
264275
append("\" lon=\"").append(Helper.round6(instruction.getFirstLon())).append("\">");
265276

266277
if (!instruction.getName().isEmpty())
267-
output.append("<desc>").append(instruction.getTurnDescription(tr)).append("</desc>");
278+
output.append("<desc>").append(simpleXMLEscape(instruction.getTurnDescription(tr))).append("</desc>");
268279

269280
output.append("<extensions>");
270281
output.append("<gh:distance>").append(Helper.round(instruction.getDistance(), 1)).append("</gh:distance>");

core/src/test/java/com/graphhopper/util/InstructionListTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,13 @@ public void testFind()
534534

535535
// query north-west of pillar node n , get instruction for fourth edge
536536
assertEquals("4-5", wayList.find(15.21, 9.85, 100000).getName());
537+
}
537538

539+
@Test
540+
public void testXMLEscape_issue572()
541+
{
542+
assertEquals("_", InstructionList.simpleXMLEscape("<"));
543+
assertEquals("_blup_", InstructionList.simpleXMLEscape("<blup>"));
544+
assertEquals("a&amp;b", InstructionList.simpleXMLEscape("a&b"));
538545
}
539546
}

0 commit comments

Comments
 (0)