Merge pull request #247 from probins/kmlatts
KML: write attributes; add option for kvp attributes
This commit is contained in:
@@ -64,9 +64,25 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
||||
* APIProperty: extractAttributes
|
||||
* {Boolean} Extract attributes from KML. Default is true.
|
||||
* Extracting styleUrls requires this to be set to true
|
||||
* Note that currently only Data and SimpleData
|
||||
* elements are handled.
|
||||
*/
|
||||
extractAttributes: true,
|
||||
|
||||
/**
|
||||
* APIProperty: kvpAttributes
|
||||
* {Boolean} Only used if extractAttributes is true.
|
||||
* If set to true, attributes will be simple
|
||||
* key-value pairs, compatible with other formats,
|
||||
* Any displayName elements will be ignored.
|
||||
* If set to false, attributes will be objects,
|
||||
* retaining any displayName elements, but not
|
||||
* compatible with other formats. Any CDATA in
|
||||
* displayName will be read in as a string value.
|
||||
* Default is false.
|
||||
*/
|
||||
kvpAttributes: false,
|
||||
|
||||
/**
|
||||
* Property: extractStyles
|
||||
* {Boolean} Extract styles from KML. Default is false.
|
||||
@@ -1078,12 +1094,16 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
||||
var valueNode = data.getElementsByTagName("value");
|
||||
if (valueNode.length) {
|
||||
ed['value'] = this.getChildValue(valueNode[0]);
|
||||
}
|
||||
var nameNode = data.getElementsByTagName("displayName");
|
||||
if (nameNode.length) {
|
||||
ed['displayName'] = this.getChildValue(nameNode[0]);
|
||||
}
|
||||
attributes[key] = ed;
|
||||
if (this.kvpAttributes) {
|
||||
attributes[key] = ed['value'];
|
||||
} else {
|
||||
var nameNode = data.getElementsByTagName("displayName");
|
||||
if (nameNode.length) {
|
||||
ed['displayName'] = this.getChildValue(nameNode[0]);
|
||||
}
|
||||
attributes[key] = ed;
|
||||
}
|
||||
}
|
||||
var simpleDataNodes = node.getElementsByTagName("SimpleData");
|
||||
for (i = 0, len = simpleDataNodes.length; i < len; i++) {
|
||||
@@ -1091,8 +1111,12 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
||||
data = simpleDataNodes[i];
|
||||
key = data.getAttribute("name");
|
||||
ed['value'] = this.getChildValue(data);
|
||||
ed['displayName'] = key;
|
||||
attributes[key] = ed;
|
||||
if (this.kvpAttributes) {
|
||||
attributes[key] = ed['value'];
|
||||
} else {
|
||||
ed['displayName'] = key;
|
||||
attributes[key] = ed;
|
||||
}
|
||||
}
|
||||
|
||||
return attributes;
|
||||
@@ -1209,7 +1233,14 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
||||
var geometryNode = this.buildGeometryNode(feature.geometry);
|
||||
placemarkNode.appendChild(geometryNode);
|
||||
|
||||
// TBD - deal with remaining (non name/description) attributes.
|
||||
// output attributes as extendedData
|
||||
if (feature.attributes) {
|
||||
var edNode = this.buildExtendedData(feature.attributes);
|
||||
if (edNode) {
|
||||
placemarkNode.appendChild(edNode);
|
||||
}
|
||||
}
|
||||
|
||||
return placemarkNode;
|
||||
},
|
||||
|
||||
@@ -1440,5 +1471,48 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
||||
return point.x + "," + point.y;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: buildExtendedData
|
||||
*
|
||||
* Parameters:
|
||||
* attributes - {Object}
|
||||
*
|
||||
* Returns
|
||||
* {DOMElement} A KML ExtendedData node or {null} if no attributes.
|
||||
*/
|
||||
buildExtendedData: function(attributes) {
|
||||
var extendedData = this.createElementNS(this.kmlns, "ExtendedData");
|
||||
for (attributeName in attributes) {
|
||||
// empty, name, description, styleUrl attributes ignored
|
||||
if (attributes[attributeName] && attributeName != "name" && attributeName != "description" && attributeName != "styleUrl") {
|
||||
var data = this.createElementNS(this.kmlns, "Data");
|
||||
data.setAttribute("name", attributeName);
|
||||
var value = this.createElementNS(this.kmlns, "value");
|
||||
if (typeof attributes[attributeName] == "object") {
|
||||
// cater for object attributes with 'value' properties
|
||||
// other object properties will output an empty node
|
||||
if (attributes[attributeName].value) {
|
||||
value.appendChild(this.createTextNode(attributes[attributeName].value));
|
||||
}
|
||||
if (attributes[attributeName].displayName) {
|
||||
var displayName = this.createElementNS(this.kmlns, "displayName");
|
||||
// displayName always written as CDATA
|
||||
displayName.appendChild(this.getXMLDoc().createCDATASection(attributes[attributeName].displayName));
|
||||
data.appendChild(displayName);
|
||||
}
|
||||
} else {
|
||||
value.appendChild(this.createTextNode(attributes[attributeName]));
|
||||
}
|
||||
data.appendChild(value);
|
||||
extendedData.appendChild(data);
|
||||
}
|
||||
}
|
||||
if (this.isSimpleContent(extendedData)) {
|
||||
return null;
|
||||
} else {
|
||||
return extendedData;
|
||||
}
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Format.KML"
|
||||
});
|
||||
|
||||
@@ -198,21 +198,35 @@
|
||||
t.ok(style.t, "getStyle returns copy of style rather than reference");
|
||||
}
|
||||
function test_Format_KML_extendedData(t) {
|
||||
t.plan(2);
|
||||
t.plan(6);
|
||||
var f = new OpenLayers.Format.KML();
|
||||
var features = f.read(OpenLayers.Util.getElement("kml_extendeddata").value);
|
||||
t.eq(features[0].attributes.all_bridges.value, "3030", "read value from extendeddata correctly.");
|
||||
t.eq(features[0].attributes.all_bridges.displayName, "all bridges", "read displayName from extendeddata correctly.");
|
||||
t.eq(features[0].attributes.holeYardage.value, "234", "read value from extendeddata correctly.");
|
||||
t.eq(features[0].attributes.holeYardage.displayName, "<b><i>The yardage is </i></b>", "read displayName from extendeddata correctly.");
|
||||
t.eq(f.read(f.write(features[0]))[0].attributes.holeYardage.value, features[0].attributes.holeYardage.value, "attribute value written correctly");
|
||||
t.eq(f.read(f.write(features[0]))[0].attributes.holeYardage.displayName, features[0].attributes.holeYardage.displayName, "attribute displayName written correctly");
|
||||
f.kvpAttributes = true;
|
||||
features = f.read(OpenLayers.Util.getElement("kml_extendeddata").value);
|
||||
t.eq(features[0].attributes.holeYardage, "234", "read kvp value from extendeddata correctly.");
|
||||
t.eq(f.read(f.write(features[0]))[0].attributes.holeYardage, features[0].attributes.holeYardage, "kvp attribute value written correctly");
|
||||
}
|
||||
|
||||
function test_Format_KML_extendedData_SchemaData(t) {
|
||||
t.plan(4);
|
||||
t.plan(10);
|
||||
var f = new OpenLayers.Format.KML();
|
||||
var features = f.read(OpenLayers.Util.getElement("kml_extendeddata2").value);
|
||||
t.eq(features[0].attributes.TrailHeadName.value, "Pi in the sky", "read value from extendeddata (schema data) correctly.");
|
||||
t.eq(features[0].attributes.TrailHeadName.displayName, "TrailHeadName", "read displayName from extendeddata correctly");
|
||||
t.eq(features[0].attributes.ElevationGain.value, "10", "read value from extendeddata (schema data) correctly.");
|
||||
t.eq(features[0].attributes.ElevationGain.displayName, "ElevationGain", "read displayName from extendeddata correctly");
|
||||
t.eq(f.read(f.write(features[0]))[0].attributes.TrailHeadName.value, features[0].attributes.TrailHeadName.value, "attribute value from extendeddata (schema data) written correctly");
|
||||
t.eq(f.read(f.write(features[0]))[0].attributes.ElevationGain.value, features[0].attributes.ElevationGain.value, "attribute value from extendeddata (schema data) written correctly");
|
||||
f.kvpAttributes = true;
|
||||
features = f.read(OpenLayers.Util.getElement("kml_extendeddata2").value);
|
||||
t.eq(features[0].attributes.TrailHeadName, "Pi in the sky", "read kvp value from extendeddata (schema data) correctly.");
|
||||
t.eq(features[0].attributes.ElevationGain, "10", "read kvp value from extendeddata (schema data) correctly.");
|
||||
t.eq(f.read(f.write(features[0]))[0].attributes.TrailHeadName, features[0].attributes.TrailHeadName, "kvp attribute value from extendeddata (schema data) written correctly");
|
||||
t.eq(f.read(f.write(features[0]))[0].attributes.ElevationGain, features[0].attributes.ElevationGain, "kvp attribute value from extendeddata (schema data) written correctly");
|
||||
}
|
||||
|
||||
function test_Format_KML_placemarkName(t) {
|
||||
@@ -287,49 +301,61 @@
|
||||
</head>
|
||||
<body>
|
||||
<textarea id="kml_extendeddata" style="display:none">
|
||||
<kml xmlns="http://earth.google.com/kml/2.2">
|
||||
<Document>
|
||||
<Placemark>
|
||||
<styleUrl>#default</styleUrl>
|
||||
|
||||
|
||||
|
||||
|
||||
<ExtendedData>
|
||||
<Data name='all_bridges'>
|
||||
<displayName><![CDATA[all bridges]]></displayName>
|
||||
<value><![CDATA[3030]]></value>
|
||||
</Data>
|
||||
<Data name='latitude'>
|
||||
<displayName><![CDATA[latitude]]></displayName>
|
||||
<value><![CDATA[43]]></value>
|
||||
</Data>
|
||||
<Data name='longitude'>
|
||||
<displayName><![CDATA[longitude]]></displayName>
|
||||
<value><![CDATA[-107.55]]></value>
|
||||
</Data>
|
||||
<Data name='functionally_obsolete__percent'>
|
||||
<displayName><![CDATA[functionally obsolete, percent]]></displayName>
|
||||
<value><![CDATA[8]]></value>
|
||||
</Data>
|
||||
<Data name='structurally_deficient__percent'>
|
||||
<displayName><![CDATA[structurally deficient, percent]]></displayName>
|
||||
<value><![CDATA[13]]></value>
|
||||
</Data>
|
||||
<Data name='state'>
|
||||
<displayName><![CDATA[state]]></displayName>
|
||||
<value><![CDATA[Wyoming]]></value>
|
||||
</Data>
|
||||
</ExtendedData>
|
||||
|
||||
|
||||
<Point>
|
||||
<coordinates>-107.55,43.0</coordinates>
|
||||
</Point>
|
||||
|
||||
|
||||
</Placemark>
|
||||
</Document>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kml xmlns="http://www.opengis.net/kml/2.2">
|
||||
<Document>
|
||||
<name>Entity-Replacement</name>
|
||||
<Placemark>
|
||||
<name>Club house</name>
|
||||
<ExtendedData>
|
||||
<Data name="holeNumber">
|
||||
<displayName><![CDATA[
|
||||
<b>This is hole </b>
|
||||
]]></displayName>
|
||||
<value>1</value>
|
||||
</Data>
|
||||
<Data name="holePar">
|
||||
<displayName><![CDATA[
|
||||
<i>The par for this hole is </i>
|
||||
]]></displayName>
|
||||
<value>4</value>
|
||||
</Data>
|
||||
<Data name="holeYardage">
|
||||
<displayName><![CDATA[<b><i>The yardage is </i></b>]]></displayName>
|
||||
<value>234</value>
|
||||
</Data>
|
||||
</ExtendedData>
|
||||
<Point>
|
||||
<coordinates>-111.956,33.5043</coordinates>
|
||||
</Point>
|
||||
</Placemark>
|
||||
<Placemark>
|
||||
<name>By the lake</name>
|
||||
<ExtendedData>
|
||||
<Data name="holeNumber">
|
||||
<displayName><![CDATA[
|
||||
<b>This is hole </b>
|
||||
]]></displayName>
|
||||
<value>5</value>
|
||||
</Data>
|
||||
<Data name="holePar">
|
||||
<displayName><![CDATA[
|
||||
<i>The par for this hole is </i>
|
||||
]]></displayName>
|
||||
<value>5</value>
|
||||
</Data>
|
||||
<Data name="holeYardage">
|
||||
<displayName><![CDATA[
|
||||
<b><i>The yardage is </i></b>
|
||||
]]></displayName>
|
||||
<value>523</value>
|
||||
</Data>
|
||||
</ExtendedData>
|
||||
<Point>
|
||||
<coordinates>-111.95,33.5024</coordinates>
|
||||
</Point>
|
||||
</Placemark>
|
||||
</Document>
|
||||
</kml>
|
||||
</textarea>
|
||||
<textarea id="kml_extendeddata2" style="display:none">
|
||||
|
||||
Reference in New Issue
Block a user