基于属性值匹配提取节点值的XSLT转换求助
解决XSLT中基于属性匹配提取节点值的问题
看了你提供的示例XML、期望输出和尝试的XSLT代码,能发现你现在的代码存在几个关键问题:比如定义了重复的match="/"模板(XSLT里同一匹配模式只能有一个有效模板),key的使用逻辑没对应上需求,而且没有聚焦到核心的<field>元素处理上。
下面是针对你需求的完整解决方案:
正确的XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <!-- 定义key,通过identifier快速查找category --> <xsl:key name="category-by-id" match="category" use="@identifier"/> <!-- 定义key,通过identifier快速查找field-type --> <xsl:key name="fieldtype-by-id" match="field-type" use="@identifier"/> <!-- 匹配根节点,直接处理所有field元素 --> <xsl:template match="/"> <xsl:apply-templates select="root/custom/field"/> </xsl:template> <!-- 处理每个field元素 --> <xsl:template match="field"> <field identifier="{@identifier}"> <!-- 保留原有的name和description --> <xsl:copy-of select="name | description"/> <!-- 添加category-ref-name:通过category-ref找到对应的category的name --> <category-ref-name> <xsl:value-of select="key('category-by-id', @category-ref)/name"/> </category-ref-name> <!-- 获取对应的field-type节点 --> <xsl:variable name="target-fieldtype" select="key('fieldtype-by-id', @field-type-ref)"/> <!-- 添加field-type-ref:提取persistence-class-name的最后一部分(比如java.lang.Long → Long) --> <field-type-ref> <xsl:choose> <xsl:when test="contains($target-fieldtype/persistence-class-name, '.')"> <xsl:value-of select="substring-after($target-fieldtype/persistence-class-name, substring-before($target-fieldtype/persistence-class-name, '.') )"/> <!-- 上面的写法对于多级包名也适用,比如a.b.c.Class → Class --> </xsl:when> <xsl:otherwise> <xsl:value-of select="$target-fieldtype/persistence-class-name"/> </xsl:otherwise> </xsl:choose> </field-type-ref> <!-- 添加proxy-entity-ref:取field-type的proxy-ref属性值 --> <proxy-entity-ref> <xsl:value-of select="$target-fieldtype/@proxy-ref"/> </proxy-entity-ref> </field> </xsl:template> </xsl:stylesheet>
代码解释
- Key定义:
category-by-id和fieldtype-by-id两个key分别用来快速通过identifier属性查找对应的<category>和<field-type>节点,避免了繁琐的路径遍历,提升效率。 - 根模板:直接定位到所有需要处理的
<field>元素,开始转换。 - Field模板:
- 复制原
<field>的identifier属性,保留原有结构。 - 用
<xsl:copy-of>直接复制原有的<name>和<description>节点,不用重新构造。 - 通过
key('category-by-id', @category-ref)找到对应的<category>,提取它的<name>值作为<category-ref-name>。 - 提取
persistence-class-name的最后一部分:利用contains判断是否有包名分隔符,用substring-after和substring-before组合截取最后一段类名。 - 直接取对应
<field-type>的proxy-ref属性值作为<proxy-entity-ref>的内容。
- 复制原
验证输出
将上述XSLT应用到你提供的示例XML,会生成完全符合你期望的输出结果:
<field identifier="ArticleID"> <name>%field.name</name> <description>%field.Article.description</description> <category-ref-name>%category.parent</category-ref-name> <field-type-ref>Long</field-type-ref> <proxy-entity-ref>TypeA</proxy-entity-ref> </field> <field identifier="ArticleName"> <name>%field.name.text</name> <description>%field.Articletext.description</description> <category-ref-name>%category.Texts</category-ref-name> <field-type-ref>String</field-type-ref> <proxy-entity-ref>TypeB</proxy-entity-ref> </field>
内容的提问来源于stack exchange,提问作者Tester
相关产品推荐
相关产品推荐

