Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xml 使用XSLT筛选未引用的成员节点_Xml_Xslt - Fatal编程技术网

Xml 使用XSLT筛选未引用的成员节点

Xml 使用XSLT筛选未引用的成员节点,xml,xslt,Xml,Xslt,OpenStreetMapXML文档由一组“节点”元素和一组“方式”元素组成 “节点”元素可以(可选)嵌套“标记”元素 “方式”元素由“节点”元素的有序列表组成,由嵌套元素“nd”引用,其属性“ref”指向“节点”元素处的属性“id” 这里有一个例子: <?xml version="1.0" encoding="UTF-8"?> <osm version="0.6" generator="CGImap 0.0.2"> <node id="1726631203"

OpenStreetMapXML文档由一组“节点”元素和一组“方式”元素组成

“节点”元素可以(可选)嵌套“标记”元素

“方式”元素由“节点”元素的有序列表组成,由嵌套元素“nd”引用,其属性“ref”指向“节点”元素处的属性“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进行以下转换

  • 筛选所有未被any way元素引用的节点元素
  • 筛选引用源xml文档中未包含的节点元素的方式
  • 将属性“visible”更改为“false”,更改为任何没有“tag”子元素的“node”元素

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

类似的内容应该可以工作:

<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:copy除了visible属性之外的所有子元素,而不是简单地使用xsl:copy of)。

这似乎有效:

<?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中的位将visible属性设置为false。这是一种更改属性值的方法,无需单独复制所有属性;但它忽略除标记之外的任何子元素

我还没有提到过滤方式元素

我的问题是,如何使用XSLT执行以下操作 转变

  • 筛选所有未被any way元素引用的节点元素

  • 筛选引用源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>
说明

<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>
  • 标识规则由三个模板覆盖,每个模板实现三个需求中的一个

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

  • 我们使用键通过其
    id
    属性方便有效地查找
    node
    s,并通过其
    ref
    属性方便有效地查找
    nd
    s

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


  • 谢谢你如此完整的回答@Dimitre!。试着理解这一逻辑:在声明键时,为什么要在匹配条件中写入“way/nd”和“node”,而不是“/osm/way/nd”和“/osm/node”?我的问题是,我不知道此行“key”函数的当前上下文路径在哪里:换句话说,在我看来,key函数中的路径应该是绝对的(正如我上面所写的)或者在node元素的上下文中,因为它是由“match”条件匹配的元素。@Sergio:match属性中的表达式是“match pattern”,通常是一个简短的相对XPath表达式。只有在需要消除歧义时才需要指定祖先。在这种情况下,我可以只使用
    match=“nd”
    ,因为
    nd
    元素只显示为
    way
    的子元素。如果他们可能是两个名字不同的父母的孩子,则需要
    way/nd
    match=“nd”
    表示(与
    xsl:template
    上指定的mtch模式完全相同):匹配当前节点的任何子节点,其名称(子节点的名称)为
    “nd”
    。您需要阅读有关匹配模式的内容才能更好地理解它们。我明白了,在上一个模板中,您为什么要编写而不是只编写?。在第二种情况下,您不会发现所有没有嵌套“标记”的“节点”元素元素?。感谢您的澄清。@Sergio:我这样做是因为我想匹配属性本身——而不是保存它的元素,标识模板负责元素——唯一必须更改的节点是属性。
    <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>