在使用WireShark的pdml输出(此处定义为http://www.nbee.org/doku.php?id=netpdl:pdml_specification)时,我试图将下面相同结构的较大文档转换为下面的示例:
原始XML:
<packet>
<proto name="geninfo" pos="0" showname="General Information" size="308">
<field name="num" pos="0" show="2574" showname="Number" value="a0e" size="308"/>
<!-- more field tags here -->
</proto>
<proto name="ip" showname="Internet Protocol Version 4" size="0" pos="0">
<field name="" show="This is a fake entry created from the metadata" size="308" pos="0" value="">
<field name="ip.src" showname="Source: 1.2.3.4 (1.2.3.4)" size="0" pos="0" show="1.2.3.4"/>
<field name="ip.src2" showname="Source: 1.2.3.4 (1.2.3.4)" hide="yes" size="0" pos="0" show="1.2.3.4"/>
<!-- more field tags here -->
</field>
<!-- more field tags here -->
</proto>
<!-- more proto tags here -->
</packet>
预期/希望/最终输出:
<packet>
<geninfo>
<pos>0</pos>
<showname>General Information</showname>
<size>308</size>
<num>
<pos>0</pos>
<show>2574</show>
<showname>Number</showname>
<value>a0e</value>
<size>308</size>
</num>
<!-- more transformed field tags here -->
</geninfo>
<ip>
<showname>Internet Protocol Version 4</showname>
<size>0</size>
<pos>0</pos>
<ip>
<show>This is a fake entry created from the metadata</show>
<size>308</size>
<pos>0</pos>
<ip.src>
<showname>Source: 1.2.3.4 (1.2.3.4)</showname>
<size>0</size>
<pos>0</pos>
<show>1.2.3.4</show>
</ip.src>
<!-- more transformed field tags here -->
</ip>
<!-- more transformed field tags here -->
</ip>
<!-- more transformed proto tags here -->
</packet>
当前的XSLT:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/transform" version="1.0">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="*[not(@hide)]">
<xsl:variable name="nameAttr" select="ancestor-or-self::*[@name][1]/@name!=''"/>
<xsl:element name="{$nameAttr}">
<xsl:for-each select="@*[name(.)!='name' and .!='']">
<xsl:element name="{name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:element>
</xst:template>
</xsl:stylesheet>
这会使用hide属性跳过所有标记,并移动剩余的标记&#39;使用name属性值创建的新元素的子标记的非名称属性,同时使用空字符串值跳过非名称属性。在name属性值为空字符串的情况下,我打算使用祖先或自身轴来查找第一个非空名称属性值,以递归方式搜索祖先,知道每个proto标记将具有非空名称属性值,如果搜索到目前为止。
获取第一个祖先或自我非空属性名称值的语法的任何帮助(它当前返回@name!=&#39;&#39;)和任何xslt样式的布尔值/好的做法评论表示赞赏。
答案 0 :(得分:0)
这听起来像你正在寻找的是
<xsl:variable name="nameAttr" select="ancestor-or-self::*[@name != ''][1]"/>
要了解为什么这会有效,您需要了解XPath的一般比较运算符的工作方式。
A != value
实际上意味着在A选择的所有节点中,至少有一个节点不等于值。&#34;
在没有@name
属性的元素上,子表达式@name
不会选择任何节点,因此!=
一般比较将失败。在具有@name
属性且其值为空字符串的元素上,再次比较将失败,因为@name
仅选择了一个节点,并且它等于{{1 }}。在具有非空''
属性的元素上,比较将成功。
此外,看起来你不想要
@name
而是
<xsl:element name="{@name}">
换句话说,你想要&#34;虚假条目的名称&#34; element是source属性的名称,而不是 <xsl:element name="{name(.)}">
属性的值。对? (而且,无论如何,由于您在name
中选择了一个属性,因此当前节点是一个属性,因此for-each
将无法选择任何内容,因为属性节点不能拥有属性。)
答案 1 :(得分:0)
在完成你所拥有的工作的同时,我想出了这个:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:template match="/packet">
<packet>
<xsl:apply-templates />
</packet>
</xsl:template>
<xsl:template match="proto[not(@hide)]">
<xsl:element name="{@name}">
<xsl:apply-templates select="*|@*" />
</xsl:element>
</xsl:template>
<xsl:template match="field[@name != '']">
<xsl:element name="{@name}">
<xsl:apply-templates select="*|@*" />
</xsl:element>
</xsl:template>
<xsl:template match="field[@name = '']">
<xsl:element name="{ancestor::*[@name != ''][1]/@name}">
<xsl:apply-templates select="*|@*" />
</xsl:element>
</xsl:template>
<xsl:template match="@*[name() != 'name']">
<xsl:element name="{name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
与您的原始问题相关,这里是使用非空@name的祖先的XPath:
<xsl:element name="{ancestor::*[@name != ''][1]/@name}">
但是你确实需要进行一些重组才能以可维护的方式完成这项工作 - 尝试考虑使用模板而不是每个循环 - 它将为您提供更加模块化和灵活的设计。在上面的样式表中,有一个匹配根节点(/ packet)的模板,没有hide属性的proto节点,具有填充名称的字段节点,不具有填充名称的字段节点,以及属于'n'的属性“名称”属性。
答案 2 :(得分:0)
想要提供我的最终解决方案(几乎完全基于Dan Field的答案),并且无法将其纳入评论:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="yes"/>
<xsl:strip-space elements="*">
<xsl:template match="packet">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[(name()='proto' or name()='field') and not(@hide)]">
<xsl:element name="{ancestor-or-self::*[@name!=''][1]/@name}">
<xsl:apply-templates select="* | @*"/>
</xsl:element>
</xsl:template>
<xsl:template match="@*[name()!='name' and .!='']">
<xsl:element name="{name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template match="@*[name()='name']"/>
</xsl:stylesheet>