2014-01-16 153 views
0

我需要转换XML文件的结构,并认为XSLT可能是最好的解决方案(这就是它的正确之处?)我对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

输入有'field code =“123”',为什么输出有'field code =“124”'?你可以使用XSLT 2.0吗?使用'xsl:template match =“field”> ...'。 –

+0

它是*每个奇数子域*需要与以下哪一个配对,或者*每个A或K子域*?或者那是一回事吗? –

+0

@MartinHonnen字段代码=“124”在输出中是正确的。可以这么说是一种格式翻译。我在Visual Studio 2012中编写这个不确定是否支持XSLT 2.0。需要研究一下。 –

回答

1

假设XSLT 2.0处理程序等撒克逊9或Altova的或XmlPrime可以使用

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

应该做的。

+0

这可以工作!我会马上尝试一下! –

+0

根据你最近的解释,如果你需要'template match =“field ['code = 23]'',那么在'template match ='field''的情况下,改变if应该不会太难您只需要转换这些字段元素。 –

+0

这几乎奏效。在我的新124字段中的子字段代码为K而不是A ...不知道为什么...任何线索? –

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>