2

OpenStreetMap xml 文档由一组“node”元素和一组“way”元素组成(除其他外)。

“节点”元素可以(可选地)嵌套“标签”元素。

“way”元素由“node”元素的有序列表组成,由嵌套元素“nd”引用,它们的属性“ref”指向“node”元素的属性“id”。

这里有一个例子:

<?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 文档中的节点元素的方式元素。
  • 将属性“可见”更改为“假”,更改为没有“标记”子元素的任何“节点”元素。

任何其他元素都应保留在生成的 xml 中。

4

3 回答 3

1

我的问题是如何使用 XSLT 进行以下转换?

  • 过滤所有未被任何方式元素引用的节点元素。

  • 过滤引用未包含在源 xml 文档中的节点元素的方式元素。

  • 将属性“可见”更改为“假”,更改为没有“标记”子元素的任何“节点”元素。

这种转变满足了所有三个要求:

<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属性转换为):nodefalse

<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>

说明

  1. 身份规则被三个模板覆盖,每个模板实现三个要求之一。

  2. 具有空主体的两个覆盖模板实现了两个过滤要求。

  3. 我们使用键来方便有效地通过属性查找s,并通过属性node查找s 。idndref

  4. 属性值替换要求在第三个覆盖模板中实现。

于 2012-05-23T12:46:17.967 回答
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。您可以使用相同的技术来检查 tag 属性是否存在。不幸的是,当您需要更改属性时,您需要手动复制其他属性(xsl:复制除可见属性之外的所有子元素,而不是简单地使用 xsl:copy-of)。

于 2012-05-23T08:45:53.593 回答
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 测试是从上一个答案中复制的,并消除了未引用的节点。

当子标签不存在时,xsl:choose 中的位将可见属性设置为 false。这是一种无需单独复制所有属性即可更改属性值的方法;但它忽略标签以外的任何子元素。

我还没有解决方式元素的过滤问题。

于 2012-05-23T09:24:19.620 回答