2014-01-16 80 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>