OpenStreetMap xml文档由一组“node”元素和一组“way”元素组成(除此之外)。
“node”元素可以(可选)嵌套“tag”元素。
“way”元素由“node”元素的有序列表组成,由嵌套元素“nd”引用,其属性“ref”指向“node”元素处的属性“id”。 / p>
这是一个例子:
<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="CGImap 0.0.2">
<node id="1726631203" lat="50.8500083" lon="4.3553223" visible="true" version="6" changeset="9938190" timestamp="2011-11-24T22:05:32Z"/>
...
<way id="160611697" user="toSc" uid="246723" visible="true" version="1" changeset="11385198" timestamp="2012-04-22T14:57:19Z">
<nd ref="1726631203"/>
<nd ref="1726631223"/>
<nd ref="1726631213"/>
<nd ref="1726631205"/>
<nd ref="1726631185"/>
<nd ref="1726631203"/>
</way>
...
</osm>
我的问题是,如何使用XSLT进行以下转换?
任何其他元素应保留在生成的xml中。
答案 0 :(得分:1)
我的问题是,如何使用XSLT,我可以执行以下操作 转型?
过滤未被任何方式元素引用的所有节点元素。
过滤引用未包含在源xml文档中的节点元素的元素的方式。
将属性“visible”更改为“false”,更改为没有“tag”子元素的任何“node”元素。
此转换满足所有三个要求:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kND-By-Ref" match="way/nd" use="@ref"/>
<xsl:key name="kNodeById" match="node" use="@id"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node[not(key('kND-By-Ref', @id))]"/>
<xsl:template match="way[nd[not(key('kNodeById', @ref))]]"/>
<xsl:template match="node[not(tag)]/@visible">
<xsl:attribute name="visible">false</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
应用于此XML文档(适当创建以包含每个需求的大小写):
<osm version="0.6" generator="CGImap 0.0.2">
<node id="1726631203" lat="50.8500083" lon="4.3553223" visible="true"
version="6" changeset="9938190" timestamp="2011-11-24T22:05:32Z">
<tag/>
</node>
<node id="1726631223" lat="50.8500083" lon="4.3553223" visible="true"
version="6" changeset="9938190" timestamp="2011-11-24T22:05:32Z"/>
<node id="ZZZZZZZ" lat="50.8500083" lon="4.3553223" visible="true"
version="6" changeset="9938190" timestamp="2011-11-24T22:05:32Z"/>
<way id="160611697" user="toSc" uid="246723" visible="true"
version="1" changeset="11385198" timestamp="2012-04-22T14:57:19Z">
<nd ref="1726631203"/>
<nd ref="1726631223"/>
</way>
<way id="160611698" user="toSc" uid="246723" visible="true"
version="1" changeset="11385198" timestamp="2012-04-22T14:57:19Z">
<nd ref="1726631203"/>
<nd ref="1726631223"/>
<nd ref="1726631213"/>
<nd ref="1726631205"/>
<nd ref="1726631185"/>
<nd ref="1726631203"/>
</way>
</osm>
想要的正确结果(执行所有过滤并将其中一个visible
元素的node
属性转为false
)制作:
<osm version="0.6" generator="CGImap 0.0.2">
<node id="1726631203" lat="50.8500083" lon="4.3553223"
visible="true" version="6" changeset="9938190" timestamp="2011-11-24T22:05:32Z">
<tag/>
</node>
<node id="1726631223" lat="50.8500083" lon="4.3553223"
visible="false" version="6" changeset="9938190" timestamp="2011-11-24T22:05:32Z"/>
<way id="160611697" user="toSc" uid="246723" visible="true"
version="1" changeset="11385198" timestamp="2012-04-22T14:57:19Z">
<nd ref="1726631203"/>
<nd ref="1726631223"/>
</way>
</osm>
<强>解释强>:
身份规则由三个模板覆盖,每个模板都实现三个要求中的一个。
具有空体的两个覆盖模板实现了两个过滤要求。
我们使用密钥方便有效地查找node
属性id
和nd
属性ref
的<{1}}。
属性值替换要求在第三个覆盖模板中实现。
答案 1 :(得分:0)
这样的事情应该有效:
<xsl:for-each select="//osm/node">
<xsl:if test="//osm/way/nd[@ref=current()/@id]">
<xsl:copy-of select=".">
</xsl:if>
</xsl:for-each>
诀窍是,如果xpath表达式返回一个或多个结果,if节点中的测试将返回true。您可以使用相同的技术来检查标记属性是否存在。遗憾的是,当您需要更改属性时,您需要手动复制其他属性(xsl:复制除 visible 属性之外的所有子元素,而不是简单地使用xsl:copy-of)。
答案 2 :(得分:0)
这似乎有效:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="node">
<xsl:if test="//osm/way/nd[@ref=current()/@id]">
<xsl:choose>
<xsl:when test="tag">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:copy-of select="@*[not(local-name(.) = 'visible')]"/>
<xsl:attribute name="visible">false</xsl:attribute>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
xsl:if test是从上一个答案中复制的,并删除了未引用的节点。
当标记子项不存在时,xsl:choose中的位将visible属性设置为false。这是一种更改属性值而无需必须单独复制所有属性的方法;但它会忽略除标记之外的任何子元素。
我没有解决方式元素的过滤问题。