【问题标题】:XSLT transformation: flattening nested node based on its attribute valueXSLT 转换:根据属性值展平嵌套节点
【发布时间】:2014-04-06 11:24:28
【问题描述】:

我想使用 XSLT 展平 XML 文件。示例(可以有任意数量的 nodeedge 节点):

输入:

<?xml version="1.0" encoding="utf-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns">
  <graph>

    <node id="0">
      <data key="label">A</data>
      <data key="tag1">0</data>
      <data key="tag2">0</data>
    </node>

    <edge id="0" source="0" target="1">
      <data key="label">REFERENCED_TO</data>
    </edge>

  </graph>
</graphml>

期望的输出:

<?xml version="1.0" encoding="utf-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns">
  <graph>

    <node id="0" label="A">          
      <data key="tag1">0</data>
      <data key="tag2">0</data>
    </node>

    <edge id="0" source="1" target="0" label="REFERENCED_TO"/>

  </graph>
</graphml>

如何仅展平那些将key 属性设置为"label"data 标记?

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    我怎样才能只展平那些关键属性设置为的数据标签 “标签”?

    怎么样:

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:gml="http://graphml.graphdrawing.org/xmlns">
    
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <!-- add label attribute -->
    <xsl:template match="gml:node | gml:edge">
        <xsl:copy>
            <xsl:if test="gml:data[@key='label']">
                <xsl:attribute name="label"><xsl:value-of select="gml:data[@key='label']"/></xsl:attribute>
            </xsl:if>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <!-- suppress label element -->
    <xsl:template match="gml:data[@key='label']"/>
    
    </xsl:stylesheet>
    

    【讨论】:

    • 非常了不起,我写了完全相同的答案(只有很小的差异),但您已经添加了您的答案。刚刚删除了我的 - 有两个相同的没有意义。
    • 我认为这可以大大简化;看我的回答。
    【解决方案2】:

    有一些空闲时间,我想出了以下 XSLT(它基于 1.0,非常冗长)

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" 
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
                    xmlns:g="http://graphml.graphdrawing.org/xmlns"
                    exclude-result-prefixes="msxsl"
    >
        <xsl:output method="xml" indent="yes"/>
    
        <xsl:template match="/">
          <xsl:apply-templates />
        </xsl:template>
    
        <xsl:template match="*[*/@key='label']">
          <xsl:element name="{local-name()}" namespace="{namespace-uri()}">
            <xsl:copy-of select="@*"/>
          <xsl:attribute name="label">
            <xsl:value-of select="*[@key='label']/text()" />
          </xsl:attribute>
          <xsl:apply-templates select="*[not(@key='label')]"/>
          </xsl:element>
        </xsl:template>
    
        <xsl:template match="@* | node()">
            <xsl:copy>
                <xsl:apply-templates select="@* | node()"/>
            </xsl:copy>
        </xsl:template>
    
    </xsl:stylesheet>
    

    希望这会有所帮助,

    【讨论】:

      【解决方案3】:

      hor257k 的解决方案似乎包含三个针对 @key='label' 的测试。以下是对其进行改进的尝试:

      <xsl:stylesheet version="1.0" 
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:gml="http://graphml.graphdrawing.org/xmlns">
      
      <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
      <xsl:strip-space elements="*"/>
      
      <!-- identity transform -->
      <xsl:template match="@*|node()">
          <xsl:copy>
              <xsl:apply-templates select="@*|node()"/>
          </xsl:copy>
      </xsl:template>
      
      <!-- convert label element to attribute -->
      <xsl:template match="gml:data[@key='label']">
        <xsl:attribute name="label">
          <xsl:value-of select="."/>
        </xsl:attribute>
      </xsl:template>
      
      </xsl:stylesheet>
      

      为了完整起见,这里是 XSLT 3.0 版本:

      <xsl:stylesheet version="1.0" 
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:gml="http://graphml.graphdrawing.org/xmlns">
      
      <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
      <xsl:strip-space elements="*"/>
      <xsl:mode on-no-match="shallow-copy"/>
      
      <!-- convert label element to attribute -->
      <xsl:template match="gml:data[@key='label']">
        <xsl:attribute name="label" select="."/>
      </xsl:template>
      
      </xsl:stylesheet>
      

      【讨论】:

      • 恐怕您改进的 XSLT 1.0 版本&lt;data key="label"&gt; 始终是其父级的 第一个子级时才能工作。否则,您将收到类似“无法在包含元素的子元素之后创建属性节点(标签)”的错误。我不想做出这样的假设——如果我有,我会说得这么清楚。
      猜你喜欢
      • 1970-01-01
      • 2020-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-11
      • 2017-07-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多