XSLT: Convert Name/Value pair and transform an XML

ε祈祈猫儿з 提交于 2019-12-13 03:14:51

问题


I need to convert a name value pair into XML. I'm able to generate an XML, but the element name should be grouped and it should not be duplicated. Please see below. The FieldValue element contains 2 OrderItem values in the Detail node. If the FieldValue with OrderItem repeats, then the result should be grouped into one OrderItem node. Please help.

Source XML:

<SC>
	<Header>
		<Record>
			<FieldName>Schema</FieldName>
			<FieldValue>OrderHeader</FieldValue>
		</Record>
		<Record>
			<FieldName>Order</FieldName>
			<FieldValue>1234</FieldValue>
		</Record>
	</Header>
	<Detail>
		<Record>
			<FieldName>Schema</FieldName>
			<FieldValue>OrderItem</FieldValue>
		</Record>
		<Record>
			<FieldName>Item</FieldName>
			<FieldValue>1</FieldValue>
		</Record>
		<Record>
			<FieldName>Qty</FieldName>
			<FieldValue>10</FieldValue>
		</Record>
	</Detail>
	<Detail>
		<Record>
			<FieldName>Schema</FieldName>
			<FieldValue>OrderItem</FieldValue>
		</Record>
		<Record>
			<FieldName>Item</FieldName>
			<FieldValue>2</FieldValue>
		</Record>
		<Record>
			<FieldName>Qty</FieldName>
			<FieldValue>20</FieldValue>
		</Record>
	</Detail>
</SC>

Target 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>

回答1:


The grouping can be done as follows:

<?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>



回答2:


It appears that you are trying to define two XSLT templates, when one should be sufficient. You want to match on the root and then that you want to iterate over each SC/Detail.

Then, you want to take the FieldValue of the sibling of the FieldName node that is 'Item' (for item value) and 'Qty' (for quantity value), but only those listed under 'Record'.

Note: You have specified a doubly-nested <Item> in your transformed output and this solution reflects that requirement.

This XSLT should do what you are requesting:

<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>


来源:https://stackoverflow.com/questions/46502687/xslt-convert-name-value-pair-and-transform-an-xml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!