XSLT:转换名称/值对并转换XML
问题描述:
我需要将名称值对转换为XML。我能够生成一个XML,但元素名称应该分组,并且不应该重复。请看下面。 FieldValue元素在Detail节点中包含2个OrderItem值。如果带有OrderItem的FieldValue重复,那么结果应该分组到一个OrderItem节点中。请帮忙。XSLT:转换名称/值对并转换XML
源XML:
<SC>
\t <Header>
\t \t <Record>
\t \t \t <FieldName>Schema</FieldName>
\t \t \t <FieldValue>OrderHeader</FieldValue>
\t \t </Record>
\t \t <Record>
\t \t \t <FieldName>Order</FieldName>
\t \t \t <FieldValue>1234</FieldValue>
\t \t </Record>
\t </Header>
\t <Detail>
\t \t <Record>
\t \t \t <FieldName>Schema</FieldName>
\t \t \t <FieldValue>OrderItem</FieldValue>
\t \t </Record>
\t \t <Record>
\t \t \t <FieldName>Item</FieldName>
\t \t \t <FieldValue>1</FieldValue>
\t \t </Record>
\t \t <Record>
\t \t \t <FieldName>Qty</FieldName>
\t \t \t <FieldValue>10</FieldValue>
\t \t </Record>
\t </Detail>
\t <Detail>
\t \t <Record>
\t \t \t <FieldName>Schema</FieldName>
\t \t \t <FieldValue>OrderItem</FieldValue>
\t \t </Record>
\t \t <Record>
\t \t \t <FieldName>Item</FieldName>
\t \t \t <FieldValue>2</FieldValue>
\t \t </Record>
\t \t <Record>
\t \t \t <FieldName>Qty</FieldName>
\t \t \t <FieldValue>20</FieldValue>
\t \t </Record>
\t </Detail>
</SC>
目标XML:
<Order>
<OrderItem>
<Item>
<Item>1</Item>
<Qty>10</Qty>
</Item>
<Item>
<Item>2</Item>
<Qty>20</Qty>
</Item>
</OrderItem>
</Order>
XSLT:
<xsl:template match="@*|node()">
<Order>
<xsl:for-each select="Detail">
<Item>
<xsl:apply-templates select="Record[position()>1]"/>
</Item>
</xsl:for-each>
</Order>
</xsl:template>
<xsl:template match="Record">
<xsl:element name="{FieldName}">
<xsl:value-of select="FieldValue"/>
</xsl:element>
</xsl:template>
答
分组可以如下进行:
<?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="xs"
version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="SC">
<Order>
<xsl:for-each-group select="Detail" group-by="Record[1]/FieldValue">
<xsl:element name="{current-grouping-key()}">
<xsl:apply-templates select="current-group()"/>
</xsl:element>
</xsl:for-each-group>
</Order>
</xsl:template>
<xsl:template match="Detail">
<Item>
<xsl:apply-templates select="Record[position() gt 1]"/>
</Item>
</xsl:template>
<xsl:template match="Record">
<xsl:element name="{FieldName}">
<xsl:value-of select="FieldValue"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
答
看起来您正试图定义两个XSLT模板,当一个应该足够时。你想匹配根,然后你想遍历每个SC/Detail
。
然后,您想要获取'Item'(对于项目值)和'Qty'(对于数量值)的FieldName节点的兄弟的FieldValue,但只包含'Record'下列出的节点的值。
注意:您已在转换后的输出中指定了双嵌套<Item>
,此解决方案反映了该需求。
这XSLT应该做您请求的内容:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:for-each select="SC/Detail">
<Order>
<OrderItem>
<Item>
<Item>
<xsl:value-of select="Record[FieldName[text()='Item']]/FieldValue" />
</Item>
<Qty>
<xsl:value-of select="Record[FieldName[text()='Qty']]/FieldValue" />
</Qty>
</Item>
</OrderItem>
</Order>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
您好,感谢您的投入。 OrderItem元素应该从名称值对动态创建。元素/节点不是静态的。它是动态的。 – user8696326
该要求在您的问题中提供的代码中不明确。如果您可以更新您的问题(即更新您期望的目标XML的外观),那么我可以为您更新我的答案。 – jhenderson2099