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
|
* APIProperty: extractAttributes
|
||||||
* {Boolean} Extract attributes from KML. Default is true.
|
* {Boolean} Extract attributes from KML. Default is true.
|
||||||
* Extracting styleUrls requires this to be set to true
|
* Extracting styleUrls requires this to be set to true
|
||||||
|
* Note that currently only Data and SimpleData
|
||||||
|
* elements are handled.
|
||||||
*/
|
*/
|
||||||
extractAttributes: true,
|
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
|
* Property: extractStyles
|
||||||
* {Boolean} Extract styles from KML. Default is false.
|
* {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");
|
var valueNode = data.getElementsByTagName("value");
|
||||||
if (valueNode.length) {
|
if (valueNode.length) {
|
||||||
ed['value'] = this.getChildValue(valueNode[0]);
|
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");
|
var simpleDataNodes = node.getElementsByTagName("SimpleData");
|
||||||
for (i = 0, len = simpleDataNodes.length; i < len; i++) {
|
for (i = 0, len = simpleDataNodes.length; i < len; i++) {
|
||||||
@@ -1091,8 +1111,12 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
|||||||
data = simpleDataNodes[i];
|
data = simpleDataNodes[i];
|
||||||
key = data.getAttribute("name");
|
key = data.getAttribute("name");
|
||||||
ed['value'] = this.getChildValue(data);
|
ed['value'] = this.getChildValue(data);
|
||||||
ed['displayName'] = key;
|
if (this.kvpAttributes) {
|
||||||
attributes[key] = ed;
|
attributes[key] = ed['value'];
|
||||||
|
} else {
|
||||||
|
ed['displayName'] = key;
|
||||||
|
attributes[key] = ed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return attributes;
|
return attributes;
|
||||||
@@ -1209,7 +1233,14 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
|||||||
var geometryNode = this.buildGeometryNode(feature.geometry);
|
var geometryNode = this.buildGeometryNode(feature.geometry);
|
||||||
placemarkNode.appendChild(geometryNode);
|
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;
|
return placemarkNode;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1440,5 +1471,48 @@ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
|
|||||||
return point.x + "," + point.y;
|
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"
|
CLASS_NAME: "OpenLayers.Format.KML"
|
||||||
});
|
});
|
||||||
|
|||||||
+73
-47
@@ -198,21 +198,35 @@
|
|||||||
t.ok(style.t, "getStyle returns copy of style rather than reference");
|
t.ok(style.t, "getStyle returns copy of style rather than reference");
|
||||||
}
|
}
|
||||||
function test_Format_KML_extendedData(t) {
|
function test_Format_KML_extendedData(t) {
|
||||||
t.plan(2);
|
t.plan(6);
|
||||||
var f = new OpenLayers.Format.KML();
|
var f = new OpenLayers.Format.KML();
|
||||||
var features = f.read(OpenLayers.Util.getElement("kml_extendeddata").value);
|
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.holeYardage.value, "234", "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.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) {
|
function test_Format_KML_extendedData_SchemaData(t) {
|
||||||
t.plan(4);
|
t.plan(10);
|
||||||
var f = new OpenLayers.Format.KML();
|
var f = new OpenLayers.Format.KML();
|
||||||
var features = f.read(OpenLayers.Util.getElement("kml_extendeddata2").value);
|
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.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.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.value, "10", "read value from extendeddata (schema data) correctly.");
|
||||||
t.eq(features[0].attributes.ElevationGain.displayName, "ElevationGain", "read displayName from extendeddata 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) {
|
function test_Format_KML_placemarkName(t) {
|
||||||
@@ -287,49 +301,61 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<textarea id="kml_extendeddata" style="display:none">
|
<textarea id="kml_extendeddata" style="display:none">
|
||||||
<kml xmlns="http://earth.google.com/kml/2.2">
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Document>
|
<kml xmlns="http://www.opengis.net/kml/2.2">
|
||||||
<Placemark>
|
<Document>
|
||||||
<styleUrl>#default</styleUrl>
|
<name>Entity-Replacement</name>
|
||||||
|
<Placemark>
|
||||||
|
<name>Club house</name>
|
||||||
|
<ExtendedData>
|
||||||
|
<Data name="holeNumber">
|
||||||
<ExtendedData>
|
<displayName><![CDATA[
|
||||||
<Data name='all_bridges'>
|
<b>This is hole </b>
|
||||||
<displayName><![CDATA[all bridges]]></displayName>
|
]]></displayName>
|
||||||
<value><![CDATA[3030]]></value>
|
<value>1</value>
|
||||||
</Data>
|
</Data>
|
||||||
<Data name='latitude'>
|
<Data name="holePar">
|
||||||
<displayName><![CDATA[latitude]]></displayName>
|
<displayName><![CDATA[
|
||||||
<value><![CDATA[43]]></value>
|
<i>The par for this hole is </i>
|
||||||
</Data>
|
]]></displayName>
|
||||||
<Data name='longitude'>
|
<value>4</value>
|
||||||
<displayName><![CDATA[longitude]]></displayName>
|
</Data>
|
||||||
<value><![CDATA[-107.55]]></value>
|
<Data name="holeYardage">
|
||||||
</Data>
|
<displayName><![CDATA[<b><i>The yardage is </i></b>]]></displayName>
|
||||||
<Data name='functionally_obsolete__percent'>
|
<value>234</value>
|
||||||
<displayName><![CDATA[functionally obsolete, percent]]></displayName>
|
</Data>
|
||||||
<value><![CDATA[8]]></value>
|
</ExtendedData>
|
||||||
</Data>
|
<Point>
|
||||||
<Data name='structurally_deficient__percent'>
|
<coordinates>-111.956,33.5043</coordinates>
|
||||||
<displayName><![CDATA[structurally deficient, percent]]></displayName>
|
</Point>
|
||||||
<value><![CDATA[13]]></value>
|
</Placemark>
|
||||||
</Data>
|
<Placemark>
|
||||||
<Data name='state'>
|
<name>By the lake</name>
|
||||||
<displayName><![CDATA[state]]></displayName>
|
<ExtendedData>
|
||||||
<value><![CDATA[Wyoming]]></value>
|
<Data name="holeNumber">
|
||||||
</Data>
|
<displayName><![CDATA[
|
||||||
</ExtendedData>
|
<b>This is hole </b>
|
||||||
|
]]></displayName>
|
||||||
|
<value>5</value>
|
||||||
<Point>
|
</Data>
|
||||||
<coordinates>-107.55,43.0</coordinates>
|
<Data name="holePar">
|
||||||
</Point>
|
<displayName><![CDATA[
|
||||||
|
<i>The par for this hole is </i>
|
||||||
|
]]></displayName>
|
||||||
</Placemark>
|
<value>5</value>
|
||||||
</Document>
|
</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>
|
</kml>
|
||||||
</textarea>
|
</textarea>
|
||||||
<textarea id="kml_extendeddata2" style="display:none">
|
<textarea id="kml_extendeddata2" style="display:none">
|
||||||
|
|||||||
Reference in New Issue
Block a user