上一篇文章 - Add attribute based on Node name (incremental) in xsl
感谢Martin,我正在研究基于相同代码的后续项目。在这个项目中,我需要能够增加父节点,以根据原始节点创建一个有点关系的xml输出。我还需要为与当前节点相关的属性创建关系。
预期结果摘要
输入xml:
<xml>
<individual attr="test" attr2="test3" attr3="test2">
<name>
<firstname seq="1">Me</firstname>
<lastname>Last</lastname>
</name>
<addresses>
<address>
<street>1234 Main</street>
<city>Anytown</city>
<state>TX</state>
</address>
<address>
<street>4321 Central Ave</street>
<city>Bixby</city>
<state>ND</state>
</address>
</addresses>
<employeers>
<employeer>
<name>
<firstname seq3="99">Employer1</firstname>
<lastname>EmployerLast</lastname>
</name>
<addresses>
<address>
<street>1234 Employer1</street>
<city>Smallville</city>
<state>CT</state>
</address>
</addresses>
</employeer>
<employeer attr="test" attr2="test3" attr3="test2">
<name>
<firstname>Employer2</firstname>
<lastname>EmployerLast2</lastname>
</name>
<addresses>
<address>
<street>1234 Employer2</street>
<city>Nashville</city>
<state>TN</state>
</address>
</addresses>
</employeer>
</employeers>
</individual>
</xml>
当前xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output omit-xml-declaration="no" method="xml" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="/*//*[*]">
<xsl:element name="KEY">
<xsl:attribute name="name">
<xsl:value-of select="local-name()"/>_<xsl:number format="001" level="any"/>_ParentID</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="name(..)"/>_<xsl:number format="001" level="any"/>
</xsl:attribute>
</xsl:element>
<xsl:for-each select="@*">
<xsl:element name="KEY">
<!-- Trying to get the output to list:
1) the current node and increment - issue
2) the current attribute -->
<xsl:attribute name="name">
<xsl:value-of select="name(..)"/>_<xsl:number format="001" level="any"/>_<xsl:value-of select="name()"/>
</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:element>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="//*[not(*)]">
<xsl:element name="KEY">
<!-- Trying to get the output to list:
1) the parent node and increment - issue
2) the current node -->
<xsl:attribute name="name">
<xsl:value-of select="name(..)"/>_<xsl:number format="001" level="any"/>_<xsl:value-of select="local-name()"/>
</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="current()"/>
</xsl:attribute>
</xsl:element>
<xsl:for-each select="@*">
<xsl:element name="KEY">
<!-- Trying to get the output to list:
1) the parent node and increment - issue
2) the current node
3) the current attribute -->
<xsl:attribute name="name">
<xsl:value-of select="name(../..)"/>_<xsl:number format="001" level="any"/>_<xsl:value-of select="name(..)"/>_<xsl:value-of select="name()"/>
</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:element>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
代码测试位置 - http://xsltfiddle.liberty-development.net/bFukv89/2
实际与期望结果:
<?xml version="1.0" encoding="utf-16"?>
<KEY name="individual_001_ParentID" value="xml_001" />
<KEY name="individual_001_attr" value="test" />
<KEY name="individual_001_attr2" value="test3" />
<KEY name="individual_001_attr3" value="test2" />
<KEY name="name_001_ParentID" value="individual_001" />
<KEY name="name_001_firstname" value="Me" />
<KEY name="name_001_firstname_seq" value="1" />
<KEY name="name_001_lastname" value="Last" />
<KEY name="addresses_001_ParentID" value="individual_001" />
<KEY name="address_001_ParentID" value="addresses_001" />
<KEY name="address_001_street" value="1234 Main" />
<KEY name="address_001_city" value="Anytown" />
<KEY name="address_001_state" value="TX" />
<KEY name="address_002_ParentID" value="addresses_002" />
<KEY name="address_002_street" value="4321 Central Ave" />
<KEY name="address_002_city" value="Bixby" />
<KEY name="address_002_state" value="ND" />
<KEY name="employeers_001_ParentID" value="individual_001" />
<KEY name="employeer_001_ParentID" value="employeers_001" />
<KEY name="name_002_ParentID" value="employeer_002" />
<KEY name="name_002_firstname" value="Employer1" />
<!-- actual result -->
<KEY name="name_001_firstname_seq3" value="99" />
<!-- desired result as this is the secod occurrance of the parent node-->
<KEY name="name_002_firstname_seq3" value="99" />
<KEY name="name_002_lastname" value="EmployerLast" />
<KEY name="addresses_002_ParentID" value="employeer_002" />
<KEY name="address_003_ParentID" value="addresses_003" />
<KEY name="address_003_street" value="1234 Employer1" />
<KEY name="address_003_city" value="Smallville" />
<KEY name="address_003_state" value="CT" />
<KEY name="employeer_002_ParentID" value="employeers_002" />
<!-- actual result -->
<KEY name="employeer_001_attr" value="test" />
<KEY name="employeer_001_attr2" value="test3" />
<KEY name="employeer_001_attr3" value="test2" />
<!-- desired result as this is the secod occurrance of the parent node-->
<KEY name="employeer_002_attr" value="test" />
<KEY name="employeer_002_attr2" value="test3" />
<KEY name="employeer_002_attr3" value="test2" />
<KEY name="name_003_ParentID" value="employeer_003" />
<KEY name="name_003_firstname" value="Employer2" />
<KEY name="name_003_lastname" value="EmployerLast2" />
<KEY name="addresses_003_ParentID" value="employeer_003" />
<KEY name="address_004_ParentID" value="addresses_004" />
<KEY name="address_004_street" value="1234 Employer2" />
<KEY name="address_004_city" value="Nashville" />
<KEY name="address_004_state" value="TN" />
答案 0 :(得分:1)
如果我们将编号保存在变量中,例如
<xsl:variable name="first_count">
<xsl:number format="001" level="any"/>
</xsl:variable>
并使用该变量而不是重复xsl:number
<xsl:value-of select="$first_count"/>
我们可以达到你想要的结果。修改后的样式表如下:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output omit-xml-declaration="no" method="xml" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="/*//*[*]">
<xsl:variable name="first_count">
<xsl:number format="001" level="any"/>
</xsl:variable>
<xsl:element name="KEY">
<xsl:attribute name="name">
<xsl:value-of select="local-name()"/>_<xsl:value-of select="$first_count"/>_ParentID</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="name(..)"/>_<xsl:value-of select="$first_count"/>
</xsl:attribute>
</xsl:element>
<xsl:for-each select="@*">
<xsl:element name="KEY">
<!-- Trying to get the output to list:
1) the current node and increment - issue
2) the current attribute -->
<xsl:attribute name="name">
<xsl:value-of select="name(..)"/>_<xsl:value-of select="$first_count"/>_<xsl:value-of select="name()"/>
</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:element>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="//*[not(*)]">
<xsl:variable name="second_count">
<xsl:number format="001" level="any"/>
</xsl:variable>
<xsl:element name="KEY">
<!-- Trying to get the output to list:
1) the parent node and increment - issue
2) the current node -->
<xsl:attribute name="name">
<xsl:value-of select="name(..)"/>_<xsl:value-of select="$second_count"/>_<xsl:value-of select="local-name()"/>
</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="current()"/>
</xsl:attribute>
</xsl:element>
<xsl:for-each select="@*">
<xsl:element name="KEY">
<!-- Trying to get the output to list:
1) the parent node and increment - issue
2) the current node
3) the current attribute -->
<xsl:attribute name="name">
<xsl:value-of select="name(../..)"/>_<xsl:value-of select="$second_count"/>_<xsl:value-of select="name(..)"/>_<xsl:value-of select="name()"/>
</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:element>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
答案 1 :(得分:1)
我认为你可以通过捕获变量中的名称/数字并将其作为参数传递给apply-templates来简化样式表。
您还应该能够为没有子元素的所有属性和元素使用单个模板。
似乎没有理由使用xsl:element
而不是创建文字结果元素。
我一直使用local-name()
。如果需要包含任何名称空间前缀,请改用name()
。
我也使用过XSLT 2.0,因为它是样式表中指定的版本。在下面的示例链接中,我将引擎更改为Saxon-HE而不是MS XslCompiledTransform(这是一个1.0处理器)。
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*" priority="1">
<xsl:apply-templates select="@*|*"/>
</xsl:template>
<xsl:template match="*">
<xsl:param name="parentInfo"/>
<xsl:variable name="nbr">
<xsl:number format="000" level="any"/>
</xsl:variable>
<xsl:variable name="parentNbr">
<xsl:number format="000" level="any" select=".."/>
</xsl:variable>
<KEY
name="{string-join((local-name(),$nbr,'ParentID'),'_')}"
value="{string-join((local-name(..),$parentNbr),'_')}"/>
<xsl:apply-templates select="@*,*">
<xsl:with-param name="parentInfo"
select="string-join((local-name(),$nbr),'_')"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="@*|*[not(*)]">
<xsl:param name="parentInfo"/>
<KEY
name="{string-join((
if (self::attribute() and not(../../*[*])) then
($parentInfo,local-name(..)) else $parentInfo,
local-name()),'_')}"
value="{.}"
/>
<xsl:apply-templates select="@*">
<xsl:with-param name="parentInfo" select="$parentInfo"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
<强>输出强>
<KEY name="individual_001_ParentID" value="xml_001"/>
<KEY name="individual_001_attr" value="test"/>
<KEY name="individual_001_attr2" value="test3"/>
<KEY name="individual_001_attr3" value="test2"/>
<KEY name="name_001_ParentID" value="individual_001"/>
<KEY name="name_001_firstname" value="Me"/>
<KEY name="name_001_firstname_seq" value="1"/>
<KEY name="name_001_lastname" value="Last"/>
<KEY name="addresses_001_ParentID" value="individual_001"/>
<KEY name="address_001_ParentID" value="addresses_001"/>
<KEY name="address_001_street" value="1234 Main"/>
<KEY name="address_001_city" value="Anytown"/>
<KEY name="address_001_state" value="TX"/>
<KEY name="address_002_ParentID" value="addresses_001"/>
<KEY name="address_002_street" value="4321 Central Ave"/>
<KEY name="address_002_city" value="Bixby"/>
<KEY name="address_002_state" value="ND"/>
<KEY name="employeers_001_ParentID" value="individual_001"/>
<KEY name="employeer_001_ParentID" value="employeers_001"/>
<KEY name="name_002_ParentID" value="employeer_001"/>
<KEY name="name_002_firstname" value="Employer1"/>
<KEY name="name_002_firstname_seq3" value="99"/>
<KEY name="name_002_lastname" value="EmployerLast"/>
<KEY name="addresses_002_ParentID" value="employeer_001"/>
<KEY name="address_003_ParentID" value="addresses_002"/>
<KEY name="address_003_street" value="1234 Employer1"/>
<KEY name="address_003_city" value="Smallville"/>
<KEY name="address_003_state" value="CT"/>
<KEY name="employeer_002_ParentID" value="employeers_001"/>
<KEY name="employeer_002_attr" value="test"/>
<KEY name="employeer_002_attr2" value="test3"/>
<KEY name="employeer_002_attr3" value="test2"/>
<KEY name="name_003_ParentID" value="employeer_002"/>
<KEY name="name_003_firstname" value="Employer2"/>
<KEY name="name_003_lastname" value="EmployerLast2"/>
<KEY name="addresses_003_ParentID" value="employeer_002"/>
<KEY name="address_004_ParentID" value="addresses_003"/>
<KEY name="address_004_street" value="1234 Employer2"/>
<KEY name="address_004_city" value="Nashville"/>
<KEY name="address_004_state" value="TN"/>
工作示例:
答案 2 :(得分:0)
至少在XSLT 2或3中,您还可以将编号更改为例如
<xsl:attribute name="name">
<xsl:value-of select="name(..)"/>_<xsl:number format="001" select=".." level="any"/>_<xsl:value-of select="name()"/>
</xsl:attribute>
计算属性的父元素,请参阅https://www.w3.org/TR/xslt20/#number。