我需要转换XML文件的结构,并认为XSLT可能是最好的解决方案(这就是它的正确用途吗?)我对XSLT有一些经验,但它有点限制,所以我需要一些指导。
情景如下;我有一个包含一个或多个记录的XML。每条记录都有一组字段,每个字段都有一组子字段。子字段的顺序很重要。需要做的是输入结构需要进行转换,以便每次出现的子字段代码A和K都应该在输出中产生一个新字段(新代码和子字段K重命名为A)字段A或K后面的字段,如下例所示。子字段K的数量是任意的,并且可能因记录而不同,xslt需要略微一般。
这是我的输入XML:
<?xml version="1.0" encoding="UTF-8" ?>
<record>
<field code="123">
<subfield code="A">Abc</subfield>
<subfield code="B">De</subfield>
<subfield code="K">Fgh</subfield>
<subfield code="C">IJ</subfield>
<subfield code="K">Klmn</subfield>
<subfield code="D">OP</subfield>
</field>
<field>... more datafields... </field>
</record>
所需的输出如下:
<?xml version="1.0" encoding="UTF-8" ?>
<record>
<field code="124">
<subfield code="A">Abc</subfield>
<subfield code="B">De</subfield>
</field>
<field code="124">
<subfield code="A">Fgh</subfield>
<subfield code="C">IJ</subfield>
</field>
<field code="124">
<subfield code="A">Klmn</subfield>
<subfield code="D">OP</subfield>
</field>
<field>... more datafields... </field>
</record>
如果有人可以提供一些样本xslt,至少指出我正确的方向,我会非常感激。
编辑:只是为了澄清。 A和K子字段之间可以有任意数量的子字段。
答案 0 :(得分:1)
假设您可以使用像Saxon 9或Altova或XmlPrime这样的XSLT 2.0处理器
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="field">
<xsl:for-each-group select="subfield" group-starting-with="subfield[@code = ('A', 'K')]">
<field code="124">
<xsl:apply-templates select="current-group()"/>
</field>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="subfield/@code[. = 'K']">
<xsl:attribute name="{name()}" select="'A'"/>
</xsl:template>
</xsl:stylesheet>
转换
<?xml version="1.0" encoding="UTF-8" ?>
<record>
<field code="123">
<subfield code="A">Abc</subfield>
<subfield code="B">De</subfield>
<subfield code="K">Fgh</subfield>
<subfield code="C">IJ</subfield>
<subfield code="K">Klmn</subfield>
<subfield code="D">OP</subfield>
</field>
<field>... more datafields... </field>
</record>
到
<record>
<field code="124">
<subfield code="A">Abc</subfield>
<subfield code="B">De</subfield>
</field>
<field code="124">
<subfield code="A">Fgh</subfield>
<subfield code="C">IJ</subfield>
</field>
<field code="124">
<subfield code="A">Klmn</subfield>
<subfield code="D">OP</subfield>
</field>
</record>
如果您需要XSLT 1.0解决方案,那么
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:key name="sub" match="subfield[not(@code = 'A' or @code = 'K')]"
use="generate-id(preceding-sibling::subfield[@code = 'A' or @code = 'K'][1])"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="field">
<xsl:apply-templates select="subfield[@code = 'A' or @code = 'K']" mode="group"/>
</xsl:template>
<xsl:template match="subfield[@code = 'A' or @code = 'K']" mode="group">
<field code="124">
<xsl:apply-templates select=". | key('sub', generate-id())"/>
</field>
</xsl:template>
<xsl:template match="subfield/@code[. = 'K']">
<xsl:attribute name="{name()}">A</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
应该这样做。
答案 1 :(得分:0)
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="subfield">
<field code="{../@code}">
<xsl:copy-of select="." />
<xsl:copy-of select="following-sibling::subfield[1]" />
</field>
</xsl:template>
<xsl:template match="record">
<xsl:apply-templates select="//subfield[position() mod 2 = 1]" />
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="record" />
</xsl:template>
</xsl:stylesheet>