xml - XSL 在 for-each 中按属性查找元素
问题描述
在我的 XML 文档中,我有以下类型的节点:
<parent>
<value id="value1" name="Y" type="number"/>
<value id="value2" name="X" type="number"/>
<value id="value3" name="Z" type="operation" op="-" args="value1;value2"/>
</parent>
我想改变它以使完整的操作看起来像这样:
<parent>
<value id="value1" name="Y" type="number" />
<value id="value2" name="X" type="number" />
<operation>
<name>Z = Y - X</name>
</operation>
</parent>
我正在为我的 xsl 模板而苦苦挣扎。这是完整的 XSL 代码:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:str="http://exslt.org/strings">
<xsl:template match="@*|node()" priority="0">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="value[@type='operation']" priority="1">
<xsl:variable name="name">
<xsl:value-of select="concat(@name, ' = ')" />
<xsl:for-each select="str:tokenize(@args, ';')">
<xsl:choose>
<xsl:when test="//value[@id=current()]">
<xsl:value-of
select="concat(//value[@id=current()]/@name, ' ', @op, ' ')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(current(), ' ', @op, ' ')" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
<operation>
<name>
<xsl:value-of select="$name" />
</name>
</operation>
</xsl:template>
</xsl:stylesheet>
在 fore-each 中,我正在检查它是否可以找到正确的节点,因为有时,操作的 @args 可能类似于args="2.00;value1"
例如。
我在 for-each 中的测试显然有问题,因为我为上面显示的输入文件得到的结果是
<?xml version="1.0" encoding="UTF-8"?>
<parent>
<value id="value1" name="Y" type="number" />
<value id="value2" name="X" type="number" />
<operation xmlns:str="http://exslt.org/strings">
<name>Z = value1 value2 </name>
</operation>
</parent>
应该进行什么测试才能获得正确值的名称?
解决方案
使用 XSLT 1 和 EXSLT str:tokenize
,您可以使用
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
exclude-result-prefixes="str"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:str="http://exslt.org/strings">
<xsl:template match="@*|node()" priority="0">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:key name="val-ref" match="value[@id]" use="@id"/>
<xsl:template match="value[@type='operation']" priority="1">
<xsl:variable name="op" select="."/>
<xsl:variable name="name">
<xsl:value-of select="concat(@name, ' = ')" />
<xsl:for-each select="str:tokenize(@args, ';')">
<xsl:if test="position() > 1">
<xsl:value-of select="concat(' ', $op/@op, ' ')"/>
</xsl:if>
<xsl:variable name="value" select="."/>
<xsl:for-each select="$op">
<xsl:choose>
<xsl:when test="key('val-ref', $value)">
<xsl:value-of
select="key('val-ref', $value)/@name" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$value" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:for-each>
</xsl:variable>
<operation>
<name>
<xsl:value-of select="$name" />
</name>
</operation>
</xsl:template>
</xsl:stylesheet>
http://xsltransform.net/3MP2uCm
使用 XSLT 3,它变得更加紧凑:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:key name="val-ref" match="value[@id]" use="@id"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="value[@op]">
<operation>
<name>
<xsl:value-of select="@name || ' = '"/>
<xsl:value-of select="tokenize(@args, ';') ! (key('val-ref', ., current()/ancestor::parent)/@name, .)[1]"
separator=" {@op} "/>
</name>
</operation>
</xsl:template>
</xsl:stylesheet>
推荐阅读
- excel - 在 Catalina 上的 Microsoft Excel 2019 上运行 vba
- python - 在python中下载文件夹
- r - 在 R 中使用 mstate
- r - 指定位置闪避中的变量顺序
- angular - Angular Ngx-Bootstrap Datepicker 下一个/上一个自定义按钮
- jquery - addClass 到每个带有数据属性标签的 div
- javascript - JSON填充表的搜索功能
- c# - 在 foreach 中添加时间/延迟以读取字符串/Visual Studio 2019 C# Win Forms
- c++ - C++:在一个程序中创建一个指针并在另一个程序中访问该位置
- jquery - javascript:如何从 JSON 对象中检索文件并将其存储到 SharePoint 文档库