使用XSLT 1.0将元素连接行和列名称的平面XML表数据转换为嵌套XML [英] Convert flat XML table data where elements are concatenated row and column names into nested XML, using XSLT 1.0
问题描述
我有XML输出代表这样输出的数据表:
I have XML output representing a table of data being output like this:
<results>
<Row1.Name>Henry</Row1.Name>
<Row1.Id>P162</Row1.Id>
<Row1.Age>23</Row1.Age>
<Row2.Name>John</Row2.Name>
<Row2.Id>P137</Row2.Id>
<Row2.Age>27</Row2.Age>
<Row3.Name>Mary</Row3.Name>
<Row3.Id>L493</Row3.Id>
<Row3.Age>32</Row3.Age>
</results>
,我想将其转换为此:
<results>
<Row>
<Name>Henry</Name>
<Id>P162<Id>
<Age>23</Age>
</Row>
<Row>
<Name>John</Name>
<Id>P137<Id>
<Age>27</Age>
</Row>
<Row>
<Name>Mary</Name>
<Id>L493<Id>
<Age>32</Age>
</Row>
</results>
我正在使用的应用程序迫使我使用XSLT 1.0,我敢肯定这确实很简单,但是我今天遇到了麻烦,所以我想问一下我的虚拟同事.
The application I am working with forces me to use XSLT 1.0, and I'm sure this is really simple, but I'm having a mental block today so I figured I'd ask my virtual colleagues.
有人有什么主意吗?
注意:修改了所需的输出,以不显示迭代行号,这正是我想要的.
NOTE: Amended the desired output to not show iterative row numbers, which is what I want.
还没有什么工作要做.还在玩着不同的东西.
Haven't got anything close to working yet. Still playing around with different things.
我想可以这样写:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="Row" select="distinct-values(*[contains(name(),'Row')])" />
<xsl:for-each select="$Row">
<xsl:variable name="rowName" select="name()" />
<Row>
<xsl:for-each select="*[contains(name(),$Row)]">
<xsl:copy select="." />
</xsl:for-each>
</Row>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
产生这个:
<results>
<Row>
<Row1.Name>Henry</Row1.Name>
<Row1.Id>P162</Row1.Id>
<Row1.Age>23</Row1.Age>
</Row>
<Row>
<Row2.Name>John</Row2.Name>
<Row2.Id>P137</Row2.Id>
<Row2.Age>27</Row2.Age>
</Row>
<Row>
<Row3.Name>Mary</Row3.Name>
<Row3.Id>L493</Row3.Id>
<Row3.Age>32</Row3.Age>
</Row>
</results>
,然后返回并使用以下命令删除所有Row#前缀:
and then go back and remove all the Row# prefixes with:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*[contains(name(),'.')]">
<xsl:variable name="Name" select="substring-after(name(),'.')" />
<xsl:element name="{$Name}">
<xsl:value-of select="." />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
虽然这两种转换都不起作用,但我认为我不能在XSLT 1.0中使用distinct-values
Neither transform works though and I don't think I can use distinct-values
with XSLT 1.0
推荐答案
这是一个分组问题,而在XSLT 1.0中解决此类问题的标准方法称为孟席亚分组.您可以定义一个键,该键以所需的方式对元素进行分组,然后对generate-id
使用技巧将每个组仅处理一个元素.在这种情况下,您希望按点名称之前的部分将元素分组:
This is a grouping problem, and the standard approach to such problems in XSLT 1.0 is called Muenchian grouping. You define a key that groups your elements in the way you want and then use a trick with generate-id
to process just one element per group. In this case you want to group elements by the part of their name before the dot:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:key name="elementByRow" match="/*/*"
use="substring-before(name(), '.')" />
<xsl:template match="/results">
<results>
<!-- pick out the first RowN.* element for each N -->
<xsl:apply-templates select="*[generate-id() =
generate-id(key('elementByRow', substring-before(name(), '.'))[1])]" />
</results>
</xsl:template>
<xsl:template match="*">
<Row>
<!-- process _all_ the elements that belong to this row -->
<xsl:for-each select="key('elementByRow', substring-before(name(), '.'))">
<xsl:element name="{substring-after(name(), '.')}">
<xsl:value-of select="." />
</xsl:element>
</xsl:for-each>
</Row>
</xsl:template>
</xsl:stylesheet>
这篇关于使用XSLT 1.0将元素连接行和列名称的平面XML表数据转换为嵌套XML的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!