求可将含几何数据的XML导入PostgreSQL的实用XSLT
用XSLT处理XML几何数据导入PostgreSQL
刚好做过类似的需求,我来给你一步步拆解怎么实现!核心思路是把XML里的几何结构转换成PostgreSQL(配合PostGIS)支持的WKT格式,再生成可执行的SQL脚本完成导入。
第一步:先明确XML结构示例
先给个典型的XML片段,方便对应理解:
<PSKs> <PSK> <ID>1</ID> <GEOMETRY> <P> <B S="10.0$20.0"/> </P> </GEOMETRY> </PSK> <PSK> <ID>2</ID> <GEOMETRY> <L> <B S="10.0$20.0$30.0$40.0$50.0$60.0"/> </L> </GEOMETRY> </PSK> <PSK> <ID>3</ID> <GEOMETRY> <MP> <B S="10.0$20.0"/> <B S="30.0$40.0"/> <B S="50.0$60.0"/> </MP> </GEOMETRY> </PSK> </PSKs>
这里我先做个类型对应假设(你可以根据实际业务调整):
<P>→ Point(单点)<L>→ LineString(线)<MP>→ MultiPoint(多点)
第二步:编写XSLT转换脚本
用XSLT 2.0(支持tokenize函数,处理字符串分割更顺手),脚本会自动把XML转换成PostgreSQL可执行的SQL:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="UTF-8"/> <!-- 主入口:生成建表SQL + 所有INSERT语句 --> <xsl:template match="/"> <!-- 先启用PostGIS扩展(如果没装的话) --> <xsl:text>CREATE EXTENSION IF NOT EXISTS postgis;</xsl:text> <xsl:text> </xsl:text> <!-- 创建存储表 --> <xsl:text>CREATE TABLE IF NOT EXISTS psk_data (id INT PRIMARY KEY, geom GEOMETRY);</xsl:text> <xsl:text> </xsl:text> <!-- 遍历每个PSK节点生成插入语句 --> <xsl:for-each select="PSKs/PSK"> <xsl:variable name="psk-id" select="ID"/> <xsl:variable name="wkt-geom"> <xsl:apply-templates select="GEOMETRY/*"/> </xsl:variable> <!-- 生成INSERT,用ST_GeomFromText把WKT转成PostGIS几何对象 --> <xsl:text>INSERT INTO psk_data (id, geom) VALUES (</xsl:text> <xsl:value-of select="$psk-id"/> <xsl:text>, ST_GeomFromText('</xsl:text> <xsl:value-of select="$wkt-geom"/> <xsl:text>', 4326));</xsl:text> <!-- 4326是WGS84坐标系,按需修改 --> <xsl:text> </xsl:text> </xsl:for-each> </xsl:template> <!-- 处理Point类型(<P>节点) --> <xsl:template match="P"> <xsl:variable name="coords" select="tokenize(B/@S, '\$')"/> <xsl:text>Point(</xsl:text> <xsl:value-of select="$coords[1]"/> <!-- X坐标 --> <xsl:text> </xsl:text> <xsl:value-of select="$coords[2]"/> <!-- Y坐标 --> <xsl:text>)</xsl:text> </xsl:template> <!-- 处理LineString类型(<L>节点) --> <xsl:template match="L"> <xsl:variable name="coord-list" select="tokenize(B/@S, '\$')"/> <xsl:text>LineString(</xsl:text> <!-- 每两个坐标一组,生成x y格式 --> <xsl:for-each select="$coord-list[position() mod 2 = 1]"> <xsl:if test="position() > 1">, </xsl:if> <xsl:value-of select="."/> <xsl:text> </xsl:text> <xsl:value-of select="$coord-list[position() + current()/position()]"/> </xsl:for-each> <xsl:text>)</xsl:text> </xsl:template> <!-- 处理MultiPoint类型(<MP>节点) --> <xsl:template match="MP"> <xsl:text>MultiPoint(</xsl:text> <xsl:for-each select="B"> <xsl:if test="position() > 1">, </xsl:if> <xsl:variable name="coords" select="tokenize(@S, '\$')"/> <xsl:text>(</xsl:text> <xsl:value-of select="$coords[1]"/> <xsl:text> </xsl:text> <xsl:value-of select="$coords[2]"/> <xsl:text>)</xsl:text> </xsl:for-each> <xsl:text>)</xsl:text> </xsl:template> </xsl:stylesheet>
第三步:执行转换并导入
1. 把XML转换成SQL脚本
用XSLT处理器(比如免费的Saxon HE版本)执行转换:
java -jar saxon9he.jar -s:你的输入文件.xml -xsl:上面的XSLT文件.xsl -o:output.sql
如果用其他处理器(比如Xalan),命令逻辑类似,调整参数即可。
2. 导入到PostgreSQL
确保你的数据库已经启用PostGIS,然后执行生成的SQL:
psql -d 你的数据库名 -U 用户名 -f output.sql
可选调整点
- 如果
<MP>实际是MultiPolygon:修改<MP>的模板,每个<B>对应多边形的环,WKT格式要写成MultiPolygon(((x1 y1, x2 y2, ..., x1 y1)))(注意闭合) - 坐标顺序如果是Y/X:调整模板里
$coords[1]和$coords[2]的顺序 - 大数据量优化:可以生成CSV格式代替SQL,用
COPY命令导入,效率更高(需要调整XSLT输出为CSV,注意WKT的引号处理)
内容的提问来源于stack exchange,提问作者ondrusu
相关产品推荐
相关产品推荐

