当前位置: 首页 > news >正文

第08章-几何输出函数

第08章:几何输出函数

8.1 几何输出函数概述

PostGIS 提供了多种几何输出函数,用于将几何对象转换为各种格式的文本或二进制表示。这些函数对于数据交换、可视化和与其他系统集成至关重要。

8.1.1 输出格式分类

┌─────────────────────────────────────────────────────────────┐
│                    几何输出格式分类                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  文本格式                                                    │
│  ├── WKT (Well-Known Text)         - OGC 标准文本格式       │
│  ├── EWKT (Extended WKT)           - PostGIS 扩展文本格式   │
│  ├── GeoJSON                       - JSON 格式              │
│  ├── GML (Geography Markup)        - XML 格式               │
│  ├── KML (Keyhole Markup)          - Google Earth 格式      │
│  └── SVG (Scalable Vector)         - 可缩放矢量图形         │
│                                                             │
│  二进制格式                                                  │
│  ├── WKB (Well-Known Binary)       - OGC 标准二进制格式     │
│  ├── EWKB (Extended WKB)           - PostGIS 扩展二进制格式 │
│  ├── TWKB (Tiny WKB)               - 紧凑二进制格式         │
│  └── MVT (Mapbox Vector Tile)      - 矢量瓦片格式           │
│                                                             │
│  其他格式                                                    │
│  ├── Encoded Polyline              - Google 编码折线        │
│  ├── GeoHash                       - 空间哈希               │
│  └── LatLonText                    - 经纬度文本             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

8.2 WKT 输出

8.2.1 ST_AsText (WKT)

-- 基本用法
SELECT ST_AsText(ST_MakePoint(116.4, 39.9));
-- POINT(116.4 39.9)SELECT ST_AsText(ST_MakeLine(ST_MakePoint(0, 0), ST_MakePoint(1, 1)));
-- LINESTRING(0 0,1 1)SELECT ST_AsText(ST_MakeEnvelope(0, 0, 1, 1));
-- POLYGON((0 0,0 1,1 1,1 0,0 0))-- 3D 几何
SELECT ST_AsText(ST_MakePoint(116.4, 39.9, 45.5));
-- POINT Z (116.4 39.9 45.5)-- 带 M 值
SELECT ST_AsText(ST_MakePointM(116.4, 39.9, 100));
-- POINT M (116.4 39.9 100)-- 4D 几何
SELECT ST_AsText(ST_GeomFromText('POINT ZM(116.4 39.9 45.5 100)'));
-- POINT ZM (116.4 39.9 45.5 100)-- 控制精度(小数位数)
SELECT ST_AsText(ST_MakePoint(116.40740001, 39.90420001), 4);
-- POINT(116.4074 39.9042)SELECT ST_AsText(ST_MakePoint(116.40740001, 39.90420001), 2);
-- POINT(116.41 39.9)-- 多几何类型
SELECT ST_AsText(ST_Collect(ST_MakePoint(0, 0),ST_MakePoint(1, 1)
));
-- MULTIPOINT((0 0),(1 1))

8.2.2 ST_AsEWKT (Extended WKT)

-- EWKT 包含 SRID 信息
SELECT ST_AsEWKT(ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326));
-- SRID=4326;POINT(116.4 39.9)SELECT ST_AsEWKT(ST_SetSRID(ST_MakePoint(116.4, 39.9, 45.5), 4326));
-- SRID=4326;POINT Z (116.4 39.9 45.5)-- 控制精度
SELECT ST_AsEWKT(ST_SetSRID(ST_MakePoint(116.40740001, 39.90420001), 4326), 4);
-- SRID=4326;POINT(116.4074 39.9042)-- 与 ST_AsText 的区别
SELECT ST_AsText(geom) AS wkt,ST_AsEWKT(geom) AS ewkt
FROM poi LIMIT 1;
-- wkt: POINT(116.4 39.9)
-- ewkt: SRID=4326;POINT(116.4 39.9)

8.3 WKB 输出

8.3.1 ST_AsBinary (WKB)

-- 获取 WKB(十六进制显示)
SELECT ST_AsBinary(ST_MakePoint(116.4, 39.9));
-- 返回 bytea 类型-- 转换为十六进制字符串
SELECT encode(ST_AsBinary(ST_MakePoint(116.4, 39.9)), 'hex');-- 指定字节序
-- 'NDR': 小端序(默认)
-- 'XDR': 大端序
SELECT encode(ST_AsBinary(ST_MakePoint(0, 0), 'NDR'), 'hex');
SELECT encode(ST_AsBinary(ST_MakePoint(0, 0), 'XDR'), 'hex');-- WKB 不包含 SRID
SELECT ST_SRID(ST_GeomFromWKB(ST_AsBinary(ST_SetSRID(ST_MakePoint(0, 0), 4326))));
-- 0(SRID 丢失)

8.3.2 ST_AsEWKB (Extended WKB)

-- EWKB 包含 SRID
SELECT encode(ST_AsEWKB(ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326)), 'hex');-- 保留 SRID
SELECT ST_SRID(ST_GeomFromEWKB(ST_AsEWKB(ST_SetSRID(ST_MakePoint(0, 0), 4326))));
-- 4326-- 指定字节序
SELECT encode(ST_AsEWKB(ST_SetSRID(ST_MakePoint(0, 0), 4326), 'XDR'), 'hex');

8.3.3 ST_AsHEXEWKB

-- 直接返回十六进制字符串
SELECT ST_AsHEXEWKB(ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326));
-- 0101000020E610000066666666662D5D4066666666E6F34340-- 等价于
SELECT encode(ST_AsEWKB(ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326)), 'hex');

8.3.4 ST_AsTWKB (Tiny WKB)

-- TWKB 是一种紧凑的二进制格式
-- 适合网络传输和存储-- 基本用法
SELECT encode(ST_AsTWKB(ST_MakePoint(116.4, 39.9)), 'hex');-- 控制精度(XY 精度)
SELECT encode(ST_AsTWKB(ST_MakePoint(116.4074, 39.9042), 4), 'hex');  -- 4位小数
SELECT encode(ST_AsTWKB(ST_MakePoint(116.4074, 39.9042), 2), 'hex');  -- 2位小数-- 完整参数
-- ST_AsTWKB(geom, precision_xy, precision_z, precision_m, include_sizes, include_bboxes)
SELECT encode(ST_AsTWKB(ST_SetSRID(ST_MakePoint(116.4074, 39.9042, 45.5), 4326),6,    -- XY 精度(6位小数)2,    -- Z 精度0,    -- M 精度true, -- 包含大小信息true  -- 包含边界框
), 'hex');-- 比较不同格式的大小
SELECT pg_column_size(ST_AsBinary(geom)) AS wkb_size,pg_column_size(ST_AsEWKB(geom)) AS ewkb_size,pg_column_size(ST_AsTWKB(geom, 6)) AS twkb_size
FROM complex_polygons
LIMIT 5;-- TWKB 聚合
SELECT encode(ST_AsTWKB(array_agg(geom),ARRAY[id]::bigint[],  -- ID 数组6
), 'hex')
FROM poi
WHERE category = '餐饮';

8.4 GeoJSON 输出

8.4.1 ST_AsGeoJSON

-- 基本用法
SELECT ST_AsGeoJSON(ST_MakePoint(116.4, 39.9));
-- {"type":"Point","coordinates":[116.4,39.9]}SELECT ST_AsGeoJSON(ST_MakeLine(ST_MakePoint(0, 0), ST_MakePoint(1, 1)));
-- {"type":"LineString","coordinates":[[0,0],[1,1]]}SELECT ST_AsGeoJSON(ST_MakeEnvelope(0, 0, 1, 1));
-- {"type":"Polygon","coordinates":[[[0,0],[0,1],[1,1],[1,0],[0,0]]]}-- 控制精度
SELECT ST_AsGeoJSON(ST_MakePoint(116.40740001, 39.90420001), 4);
-- {"type":"Point","coordinates":[116.4074,39.9042]}-- 包含 CRS 信息
SELECT ST_AsGeoJSON(ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326), 15, 2);
-- {"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:4326"}},"coordinates":[116.4,39.9]}-- 参数说明
-- ST_AsGeoJSON(geom, maxdecimaldigits, options)
-- options 位掩码:
-- 0 = 无选项
-- 1 = 包含边界框
-- 2 = 使用短 CRS(EPSG:xxxx)
-- 4 = 使用长 CRS(urn:ogc:def:crs:EPSG::xxxx)
-- 8 = GeoJSON 规范严格模式-- 包含边界框
SELECT ST_AsGeoJSON(ST_MakeEnvelope(0, 0, 1, 1), 15, 1);
-- {"type":"Polygon","bbox":[0,0,1,1],"coordinates":[[[0,0],[0,1],[1,1],[1,0],[0,0]]]}-- 3D 几何
SELECT ST_AsGeoJSON(ST_MakePoint(116.4, 39.9, 45.5));
-- {"type":"Point","coordinates":[116.4,39.9,45.5]}

8.4.2 构建完整的 GeoJSON Feature

-- 创建 GeoJSON Feature
SELECT json_build_object('type', 'Feature','geometry', ST_AsGeoJSON(geom)::json,'properties', json_build_object('id', id,'name', name,'category', category)
)
FROM poi
WHERE id = 1;-- 创建 GeoJSON FeatureCollection
SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type', 'Feature','geometry', ST_AsGeoJSON(geom)::json,'properties', json_build_object('id', id,'name', name,'category', category)))
)
FROM poi
WHERE category = '餐饮';-- 使用 row_to_json 简化
SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type', 'Feature','geometry', ST_AsGeoJSON(geom, 6)::json,'properties', to_jsonb(t) - 'geom'))
)
FROM (SELECT id, name, category, geom FROM poi) t;

8.4.3 使用 jsonb 函数

-- 使用 jsonb 构建(更高效)
SELECT jsonb_build_object('type', 'FeatureCollection','features', jsonb_agg(jsonb_build_object('type', 'Feature','id', id,'geometry', ST_AsGeoJSON(geom)::jsonb,'properties', jsonb_build_object('name', name,'category', category)))
)
FROM poi
WHERE ST_Intersects(geom, ST_MakeEnvelope(116, 39, 117, 40, 4326));

8.5 GML 和 KML 输出

8.5.1 ST_AsGML

-- 基本 GML 输出
SELECT ST_AsGML(ST_MakePoint(116.4, 39.9));
-- <gml:Point><gml:coordinates>116.4,39.9</gml:coordinates></gml:Point>-- GML 3 格式
SELECT ST_AsGML(3, ST_MakePoint(116.4, 39.9));
-- <gml:Point><gml:pos>116.4 39.9</gml:pos></gml:Point>-- 控制精度
SELECT ST_AsGML(3, ST_MakePoint(116.40740001, 39.90420001), 4);-- 包含 SRID
SELECT ST_AsGML(3, ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326), 15, 1);
-- 添加 srsName 属性-- 完整参数
-- ST_AsGML(version, geom, maxdecimaldigits, options, nprefix, id)
SELECT ST_AsGML(3,                    -- GML 版本ST_SetSRID(ST_MakePoint(116.4, 39.9), 4326),6,                    -- 精度17,                   -- options: 1(srsName) + 16(namespace)'custom',             -- 命名空间前缀'point1'              -- ID
);-- options 位掩码:
-- 1 = 输出 srsName
-- 2 = 使用长 SRID URN
-- 4 = GML 3.2 格式
-- 16 = 声明命名空间
-- 32 = LineString 使用 srsDimension

8.5.2 ST_AsKML

-- 基本 KML 输出
SELECT ST_AsKML(ST_MakePoint(116.4, 39.9));
-- <Point><coordinates>116.4,39.9</coordinates></Point>-- 控制精度
SELECT ST_AsKML(ST_MakePoint(116.40740001, 39.90420001), 4);
-- <Point><coordinates>116.4074,39.9042</coordinates></Point>-- 3D 几何(KML 使用高程)
SELECT ST_AsKML(ST_MakePoint(116.4, 39.9, 45.5));
-- <Point><coordinates>116.4,39.9,45.5</coordinates></Point>-- 带名称前缀
SELECT ST_AsKML(ST_MakePoint(116.4, 39.9), 15, 'kml');
-- <kml:Point><kml:coordinates>116.4,39.9</kml:coordinates></kml:Point>-- 创建完整的 KML 文档
SELECT '<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2"><Document><name>POI 数据</name>' ||
string_agg('<Placemark><name>' || name || '</name><description>' || COALESCE(category, '') || '</description>' ||ST_AsKML(geom) ||'</Placemark>',''
) ||'</Document>
</kml>'
FROM poi
WHERE category = '景点';

8.6 SVG 输出

8.6.1 ST_AsSVG

-- 基本 SVG 路径
SELECT ST_AsSVG(ST_MakePoint(116.4, 39.9));
-- cx="116.4" cy="-39.9"  (注意 Y 轴翻转)SELECT ST_AsSVG(ST_MakeLine(ST_MakePoint(0, 0), ST_MakePoint(1, 1)));
-- M 0 0 L 1 -1SELECT ST_AsSVG(ST_MakeEnvelope(0, 0, 1, 1));
-- M 0 0 L 0 -1 1 -1 1 0 Z-- 控制精度和相对/绝对路径
-- ST_AsSVG(geom, rel, maxdecimaldigits)
-- rel = 0: 绝对路径 (M, L)
-- rel = 1: 相对路径 (m, l)SELECT ST_AsSVG(ST_MakeEnvelope(0, 0, 1, 1), 0, 2);  -- 绝对路径
SELECT ST_AsSVG(ST_MakeEnvelope(0, 0, 1, 1), 1, 2);  -- 相对路径-- 创建 SVG 文档
WITH bounds AS (SELECT ST_XMin(ST_Collect(geom)) AS min_x,ST_YMin(ST_Collect(geom)) AS min_y,ST_XMax(ST_Collect(geom)) AS max_x,ST_YMax(ST_Collect(geom)) AS max_yFROM districts
),
svg_paths AS (SELECT id, name, ST_AsSVG(geom, 0, 2) AS pathFROM districts
)
SELECT '<svg xmlns="http://www.w3.org/2000/svg" viewBox="' || min_x || ' ' || (-max_y) || ' ' || (max_x - min_x) || ' ' || (max_y - min_y) || '">' ||string_agg('<path d="' || path || '" fill="steelblue" stroke="white" stroke-width="0.01"/>', '') ||'</svg>'
FROM bounds, svg_paths
GROUP BY min_x, min_y, max_x, max_y;

8.7 其他输出格式

8.7.1 ST_AsEncodedPolyline

-- Google 编码折线(用于 Google Maps API)
SELECT ST_AsEncodedPolyline(ST_GeomFromText('LINESTRING(-120.2 38.5,-120.95 40.7,-126.453 43.252)', 4326)
);
-- _p~iF~ps|U_ulLnnqC_mqNvxq`@-- 控制精度(默认 5)
SELECT ST_AsEncodedPolyline(ST_GeomFromText('LINESTRING(-120.2 38.5,-120.95 40.7)', 4326),6  -- 6 位精度
);-- 解码
SELECT ST_AsText(ST_LineFromEncodedPolyline('_p~iF~ps|U_ulLnnqC_mqNvxq`@'));

8.7.2 ST_GeoHash

-- 生成 GeoHash
SELECT ST_GeoHash(ST_MakePoint(116.4074, 39.9042));
-- wx4g0ffe3d (默认完整精度)-- 控制精度
SELECT ST_GeoHash(ST_MakePoint(116.4074, 39.9042), 8);
-- wx4g0ffeSELECT ST_GeoHash(ST_MakePoint(116.4074, 39.9042), 5);
-- wx4g0-- 从 GeoHash 创建几何(边界框)
SELECT ST_AsText(ST_GeomFromGeoHash('wx4g0'));
-- POLYGON((116.3671875 39.8583984375, ...))-- 获取 GeoHash 的点(中心点)
SELECT ST_AsText(ST_PointFromGeoHash('wx4g0'));-- GeoHash 网格分析
SELECT ST_GeoHash(geom, 5) AS geohash,COUNT(*) AS poi_count
FROM poi
GROUP BY ST_GeoHash(geom, 5)
ORDER BY poi_count DESC;

8.7.3 ST_AsLatLonText

-- 度分秒格式
SELECT ST_AsLatLonText(ST_MakePoint(116.4074, 39.9042));
-- 39°54'15.120"N 116°24'26.640"E-- 自定义格式
SELECT ST_AsLatLonText(ST_MakePoint(116.4074, 39.9042), 'D°M''S.SSS"');
-- 39°54'15.120" 116°24'26.640"SELECT ST_AsLatLonText(ST_MakePoint(116.4074, 39.9042), 'D.DDD°');
-- 39.904° 116.407°

8.7.4 ST_AsX3D

-- X3D 格式(3D 可视化)
SELECT ST_AsX3D(ST_MakePoint(116.4, 39.9, 45.5));
-- 116.4 39.9 45.5SELECT ST_AsX3D(ST_GeomFromText('POLYGON Z((0 0 0, 1 0 0, 1 1 0, 0 1 0, 0 0 0))'));-- 控制精度
SELECT ST_AsX3D(ST_MakePoint(116.40740001, 39.90420001, 45.5), 4);

8.8 MVT 输出

8.8.1 ST_AsMVTGeom

-- 准备 MVT 几何(坐标转换到瓦片坐标系)
SELECT ST_AsMVTGeom(geom,ST_TileEnvelope(14, 13527, 6214),  -- z/x/y 瓦片边界4096,  -- extent(瓦片像素尺寸)0,     -- buffertrue   -- clip to tile
) AS mvt_geom
FROM poi
WHERE geom && ST_TileEnvelope(14, 13527, 6214);

8.8.2 ST_AsMVT

-- 生成 MVT 瓦片
SELECT ST_AsMVT(tile, 'poi') AS mvt
FROM (SELECT id,name,category,ST_AsMVTGeom(geom,ST_TileEnvelope(14, 13527, 6214),4096,64,true) AS geomFROM poiWHERE geom && ST_TileEnvelope(14, 13527, 6214)
) AS tile;-- 创建 MVT 瓦片函数
CREATE OR REPLACE FUNCTION get_mvt_tile(z INT, x INT, y INT)
RETURNS bytea AS $$
DECLAREtile_bounds geometry;mvt bytea;
BEGINtile_bounds := ST_TileEnvelope(z, x, y);SELECT ST_AsMVT(tile, 'poi', 4096, 'geom') INTO mvtFROM (SELECT id,name,category,ST_AsMVTGeom(geom,tile_bounds,4096,64,true) AS geomFROM poiWHERE geom && tile_bounds) AS tile;RETURN mvt;
END;
$$ LANGUAGE plpgsql STABLE PARALLEL SAFE;-- 使用
SELECT get_mvt_tile(14, 13527, 6214);-- 多图层 MVT
SELECT ST_AsMVT(poi_layer, 'poi') || ST_AsMVT(road_layer, 'roads') AS mvt
FROM (SELECT id, name, ST_AsMVTGeom(geom, bounds, 4096, 64, true) AS geomFROM poi, (SELECT ST_TileEnvelope(14, 13527, 6214) AS bounds) bWHERE geom && bounds
) poi_layer,
(SELECT id, name, ST_AsMVTGeom(geom, bounds, 4096, 64, true) AS geomFROM roads, (SELECT ST_TileEnvelope(14, 13527, 6214) AS bounds) bWHERE geom && bounds
) road_layer;

8.9 格式比较与选择

8.9.1 格式特性对比

格式 人类可读 大小 SRID 3D支持 用途
WKT 调试、日志
EWKT 数据交换
WKB 程序间传输
EWKB PostGIS 内部
TWKB 网络传输
GeoJSON 部分 Web API
GML 很大 OGC 服务
KML Google Earth
MVT 矢量瓦片

8.9.2 选择建议

-- Web API(推荐 GeoJSON)
SELECT json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type', 'Feature','geometry', ST_AsGeoJSON(ST_Simplify(geom, 0.0001), 6)::json,'properties', json_build_object('id', id, 'name', name)))
)
FROM districts;-- 数据备份(推荐 EWKT 或 EWKB)
COPY (SELECT id, name, ST_AsEWKT(geom) AS geomFROM spatial_data
) TO '/tmp/backup.csv' WITH CSV HEADER;-- 移动应用(推荐 TWKB)
SELECT id, name, encode(ST_AsTWKB(geom, 5), 'base64') AS geom
FROM poi
WHERE category = '餐饮';-- 地图瓦片(推荐 MVT)
SELECT get_mvt_tile(z, x, y);-- Google Earth(推荐 KML)
SELECT ST_AsKML(geom) FROM poi;

8.10 本章小结

本章详细介绍了 PostGIS 的几何输出函数:

  1. WKT 输出:ST_AsText、ST_AsEWKT
  2. WKB 输出:ST_AsBinary、ST_AsEWKB、ST_AsTWKB
  3. GeoJSON 输出:ST_AsGeoJSON 及 FeatureCollection 构建
  4. GML/KML 输出:ST_AsGML、ST_AsKML
  5. SVG 输出:ST_AsSVG
  6. 其他格式:编码折线、GeoHash、X3D
  7. MVT 输出:矢量瓦片生成

8.11 下一步

在下一章中,我们将学习空间关系函数,包括:

  • 拓扑关系判断
  • 距离关系
  • 方向关系
  • DE-9IM 模型

相关资源

  • PostGIS 输出函数
  • GeoJSON 规范
  • KML 参考
  • MVT 规范
http://www.jsqmd.com/news/159088/

相关文章:

  • 3步掌握ClickHouse地理空间分析:告别传统GIS系统臃肿配置实战指南
  • 华美食品客户评价、信任度及原料保障解析:烘焙年货品牌年度排名 - 工业设备
  • Python图像处理终极指南:从原理到实践深度解析
  • 2025年深圳靠谱移民中介排行榜,新测评精选移民公司推荐 - mypinpai
  • Serial-Studio数据可视化方案抉择:从成本控制到技术实施的最佳实践
  • BindCraft:让蛋白质分子设计变得简单高效的AI工具
  • AI编程的残酷真相:为什么说Spec Coding是2026年最大的趋势?
  • 哇塞!2026年挖到了宝藏,这几款给视频去水印工具推荐太绝啦! - 资讯焦点
  • 第01章-NPOI概述与入门
  • 戴森球计划FactoryBluePrints蓝图选择与效率提升完整指南
  • Obsidian-Douban完整指南:将豆瓣数据智能同步到个人知识库
  • 第02章-环境搭建与项目配置
  • 基于YOLOv11的红细胞、白细胞和血小板检测系统(YOLOv11深度学习+YOLO数据集+UI界面+登录注册界面+Python项目源码+模型)
  • 2025年度个人出书机构排名:个人出书流程全揭秘!哪些靠谱机构值得选? - myqiye
  • 掌握PN532 NFC/RFID开发:从入门到精通的完整指南
  • 测试用例:不能再细分的小案例,一组集合
  • 贪心算法专题(六):步步为营的极速狂飙——「跳跃游戏 II」
  • 【收藏学习】智能主体分块:告别传统文本分割,解锁AI大模型高效检索新技能
  • 使用Fiddler捕获并分析特定网站的请求。
  • SeaTunnel数据集成:零代码自动化任务管理终极指南
  • 良心推荐!2026年这几款免费去水印工具亲测排名,绝对是干货! - 资讯焦点
  • **图文印刷的工艺密码:这些细节决定你的企业印刷品档次**
  • 第06章-Excel公式与函数
  • 2025年口碑好有创新技术的护肤连锁品牌排名:5大靠谱护肤连锁品牌选择推荐 - 工业品牌热点
  • 快速上手Janus多模态AI:3步打造智能Web应用实战指南
  • Chatterbox:5秒极速语音克隆,开启语音创作新纪元
  • 为什么PaddleOCR总是自动下载字体?3种有效解决方案帮你彻底解决
  • awsm.fish精选插件库:提升Fish Shell开发效率的终极指南
  • 虚拟机压测革命:用oha VSOCK直连技术实现300%性能飞跃
  • 第05章-Excel样式与格式化