使用XSLT过滤未引用的成员节点

时间:2012-05-23 08:07:10

标签: xml xslt

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文档中的节点元素的元素。
  • 将属性“visible”更改为“false”,更改为没有“tag”子元素的任何“node”元素。

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

3 个答案:

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

<强>解释

  1. 身份规则由三个模板覆盖,每个模板都实现三个要求中的一个。

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

  3. 我们使用密钥方便有效地查找node属性idnd属性ref的<{1}}。

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

答案 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。这是一种更改属性值而无需必须单独复制所有属性的方法;但它会忽略除标记之外的任何子元素。

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