我有一个包含类似元素的 XML 文件
<function name="negate" arg1="multivector"/>
我想转换这些元素,以便 multivector
被 8 个东西中的每一个替换,包括 vector
、bivector
、rotor
等。因此转换后的 XML 将具有 8 个 negate
元素:
<function name="negate" arg1="multivector"/>
<function name="negate" arg1="multivector3"/>
<function name="negate" arg1="vector"/>
<function name="negate" arg1="vector3"/>
<function name="negate" arg1="vector"/>
<function name="negate" arg1="bivector3"/>
<function name="negate" arg1="rotor"/>
<function name="negate" arg1="rotor3"/>
同样,我的元素有两种arg
:
<function name="add" arg1="multivector" arg2="multivector"/>
转换后的 XML 应该有 64 个 add
元素,其中 args 是 vector
的各种组合,等等,尽管我会免去我们写这些的所有痛苦明确地。
我可以弄清楚如何将 multivector
转换为我的任何一个新事物,但我不太清楚如何让它多次复制同一事物。我必须手动进行丑陋的更换吗?我可以优雅地自动循环所有 8 或 64 个东西吗?
我的基本第一步
以下是我到目前为止所得到的,但它只是做了最基本的事情,将每个 arg2="multivector"
属性替换为 arg2="vector"
。也欢迎对一般样式进行改进,因为我是 XML 的新手。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Find any arg2="multivector" attribute and replace -->
<xsl:template match="function[@arg2='multivector']/@arg2">
<xsl:attribute name="arg2">vector</xsl:attribute>
</xsl:template>
<!-- Just copy anything that didn't match above -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:transform>
最佳答案
我假设您有一些这样的输入数据:
<functions>
<function name="xxxxx" arg1="yyyyy" />
<function name="negate" arg1="multivector"/>
<function name="negate" arg1="zzzzz" />
<function name="add" arg1="multivector" arg2="multivector"/>
<function name="add" arg1="aaaaa" arg2="bbbbb" />
<function name="add" arg1="ccccc" arg2="ddddd" />
</functions>
并且您想生成一个新的 XML,保留所有现有元素,除了具有以下格式的元素:
<function name="negate" arg1="multivector"/>
和
<function name="add" arg1="multivector" arg2="multivector"/>
您希望将它们替换为 n <function name="negate" arg1="..."/>
元素和 n*n
<function name="add" arg1="..." arg2="..."/>
,同时保留 <function name="xxxxx" arg1="yyyyy" />
等元素和 <function name="negate" arg1="zzzzz" />
他们在哪里。
您可以将要用于 args 的数据放在一个单独的文件中(您也可以将它放在 XSL 文件中,为其定义一个本地命名空间)。我将使用一个包含三个元素的元素:
<?xml version="1.0" encoding="UTF-8"?>
<vectors>
<vector>vector</vector>
<vector>bivector</vector>
<vector>rotor</vector>
</vectors>
我将此文件称为 vectors.xml
.
然后将该文件读入 XSLT 样式表,存储 vector
变量中的节点集,遍历每个元素两次并生成所有组合。您还将输入文档函数存储在一个变量中,因此您可以复制不受影响的节点。
这是样式表:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:variable name="vectors" select="document('vectors.xml')/vectors"/>
<xsl:variable name="functions" select="/functions"/>
<xsl:template match="functions">
<xsl:copy>
<xsl:apply-templates select="$vectors/vector"/>
</xsl:copy>
</xsl:template>
<xsl:template match="vector">
<xsl:variable name="arg1" select="."/>
<xsl:for-each select="$functions/function">
<xsl:choose>
<xsl:when test="@name='negate' and @arg1='multivector'">
<function name="negate" arg1="{$arg1}"/>
</xsl:when>
<xsl:when test="@name='add' and @arg1='multivector' and @arg2='multivector'">
<xsl:for-each select="$vectors/vector">
<function name="add" arg1="{$arg1}" arg2="{.}"/>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
使用 functions
文件包含上面列出的数据作为输入,并具有 vectors.xml
文件也在上面列出的同一目录中,它将生成:
<functions>
<function name="something" arg1="something"/>
<function name="negate" arg1="vector"/>
<function name="negate" arg1="kkk"/>
<function name="add" arg1="vector" arg2="vector"/>
<function name="add" arg1="vector" arg2="bivector"/>
<function name="add" arg1="vector" arg2="rotor"/>
<function name="add" arg1="abc" arg2="xyz"/>
<function name="add" arg1="xyz" arg2="xyz"/>
<function name="something" arg1="something"/>
<function name="negate" arg1="bivector"/>
<function name="negate" arg1="kkk"/>
<function name="add" arg1="bivector" arg2="vector"/>
<function name="add" arg1="bivector" arg2="bivector"/>
<function name="add" arg1="bivector" arg2="rotor"/>
<function name="add" arg1="abc" arg2="xyz"/>
<function name="add" arg1="xyz" arg2="xyz"/>
<function name="something" arg1="something"/>
<function name="negate" arg1="rotor"/>
<function name="negate" arg1="kkk"/>
<function name="add" arg1="rotor" arg2="vector"/>
<function name="add" arg1="rotor" arg2="bivector"/>
<function name="add" arg1="rotor" arg2="rotor"/>
<function name="add" arg1="abc" arg2="xyz"/>
<function name="add" arg1="xyz" arg2="xyz"/>
</functions>
关于xml - 用该元素的多个副本替换 XML 元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22204763/