BaseX XQuery解析带命名空间的KML根节点无结果问题及方案问询
我正在研究垂直行业中XML在KML制图场景的应用,现有编号为58961408、1541744、1535869的相关问题回答仅给出了针对性临时解决方案,未说明底层原理。我通过Web服务生成了选民分界地图shapefile对应的KML文件,结构与前述问题中的案例一致,以<kml>作为根节点同时声明了默认命名空间:
<kml xmlns="http://www.opengis.net/kml/2.2" ...> .... </kml>
我遇到的问题是:BaseX的XQuery查询始终返回0条结果,除非先调用fn:translate()处理,但处理后返回的是选择性转义的XML子树乱码,具体形态取决于文件内的节点结构。查看BaseX解析日志发现,它将源文件识别为预格式化文本,没有可解析的节点结构。
我通过试错、参考XSL常规写法写了一个XSLT临时方案:
<KMLSource xmlns:kml="http://www.opengis.net/kml/2.2" ... > ... </KMLSource>
该方案将根节点<kml>重命名为<KMLSource>,同时将kml作为命名空间属性声明,修改后BaseX的XQuery就可以正常执行FLWOR语句查询KML内容。
但我自定义的<KMLSource>根节点是非标准的,后续可能会产生不可预估的负面影响,因此想咨询针对KML、甚至SVG(这方面问题似乎更突出)的低侵入性兼容解决方案是什么?如果存在这种通用低侵入性的转换方案,是否可以将其定为这类垂直领域的标准XML导出规范?我还没测试编号58961408的回答中提到的给根节点添加xsi命名空间的方案,不确定这是不是通用的低侵入解。
最小可复现示例
根据评论要求,提供去掉Style冗余的最小可复现示例(注:示例内容较简单):
<?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:atom="http://www.w3.org/2005/Atom"> <Document id=""> <name>Are999</name> <open>0</open> <Placemark id=""> <Snippet maxLines="0"> </Snippet> <name>1</name> <description><br><br><table class='data' ><tr class='o'><td>shpFID:</td><td>0</td></tr><tr class='e'><td>OBJECTID:</td><td>3889</td></tr><tr class='o'><td>Province:</td><td>AREA</td></tr><tr class='e'><td>CAT_B:</td><td>AREA999</td></tr><tr class='o'><td>WardNo:</td><td>1</td></tr><tr class='e'><td>WardID:</td><td>93504001</td></tr><tr class='o'><td>MapCode:</td><td>AREA999_1</td></tr><tr class='e'><td>MunicName:</td><td>Nonland</td></tr><tr class='o'><td>Shape_Leng:</td><td>1.971403</td></tr><tr class='e'><td>Shape_Area:</td><td>0.1172304</td></tr></table></description> <visibility>1</visibility> <Point> <extrude>1</extrude> <tessellate>0</tessellate> <altitudeMode>clampToGround</altitudeMode> <coordinates>29.359397617,-24.0573315119999,0 </coordinates> </Point> <styleUrl>#default</styleUrl> </Placemark> <Placemark id="994"> <Snippet maxLines="0"> </Snippet> <name>995</name> <description><br><br><table class='data' ><tr class='o'><td>shpFID:</td><td>994</td></tr><tr class='e'><td>OBJECTID:</td><td>3933</td></tr><tr class='o'><td>Province:</td><td>AREA</td></tr><tr class='e'><td>CAT_B:</td><td>AREA999</td></tr><tr class='o'><td>WardNo:</td><td>995</td></tr><tr class='e'><td>WardID:</td><td>935040995</td></tr><tr class='o'><td>MapCode:</td><td>AREA999_99</td></tr><tr class='e'><td>MunicName:</td><td>Nonland</td></tr><tr class='o'><td>Shape_Leng:</td><td>0.6676676</td></tr><tr class='e'><td>Shape_Area:</td><td>0.01426437</td></tr></table></description> <visibility>1</visibility> <styleUrl>#default</styleUrl> <Polygon id=""> <extrude>1</extrude> <tessellate>0</tessellate> <altitudeMode>clampToGround</altitudeMode> <outerBoundaryIs> <LinearRing> <coordinates>-29.1979840860001,33.577018037,0 -29.1928647940001,33.5760201429999,0 -29.1928101830001,33.5759909999999,0</coordinates> </LinearRing> </outerBoundaryIs> </Polygon> </Placemark> </Document> </kml>
普通的恒等查询会将KML包裹在<text>/<line>标签中返回,以下查询没有BaseX XQuery语法错误但返回0条结果:
let $database := db:open("nonland") for $ballot_station in $database/kml/Document/Placemark return $ballot_station
BaseX 追踪日志
编译过程:
- 打开数据库 "nonland"
- 将
db:open(database[,path])重写为document-node()项:db:open("nonland")->db:open-pre("nonland", 0) - 移除无结果的路径步:
kml - 将缓存路径步重写为空序列:
kml->() - 将缓存路径重写为空序列:
$database_0/()/Document/Placemark->() - 内联
for $ballot_station_1 in () - 内联
let $database_0 := db:open-pre("nonland", 0) - 简化FLWOR表达式:
()
优化后查询:()
返回结果:命中0项
注:示例较简单,没有足够内容用于快速编写FLWOR作为明确反例。在该GIS管辖区域,位置标记被称为Balloon,前半部分为Point类型的Placemark,后半部分为Polygon边界类型的Placemark。
已验证的部分解决方案
参考@MartinHonnen的评论添加命名空间声明:
declare default element namespace "http://www.opengis.net/kml/2.2"; let $database := db:open("nonland") for $ballot_station in $database/kml/Document/Placemark/Point return $ballot_station
该XQuery返回结果如下:
<Point xmlns="http://www.opengis.net/kml/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:atom="http://www.w3.org/2005/Atom"> <extrude>1</extrude> <tessellate>0</tessellate> <altitudeMode>clampToGround</altitudeMode> <coordinates>29.359397617,-24.0573315119999,0</coordinates> </Point>
但该方案仅在移除XML文件开头的声明串后才生效:
<?xml version="1.0" encoding="UTF-8"?>
现有标准不允许XML流中出现该声明(报错:"The processing instruction target matching "[xX][mM][lL]" is not allowed."),但KML、SVG这类非明确XML载荷的垂直领域实现通常会自带该声明作为XML标识。感谢@MartinHonnen的思路,现在想请教:随着XML在越来越多非预期场景中出现,有没有通用的低侵入性workaround?我能想到的是做显式检查:如果载荷是XML就移除开头的处理指令声明,为什么相关实现不做这种无操作兼容呢?
内容的提问来源于stack exchange,提问作者MKhomo

