想要使用XSLT格式化具有混合内容的XML文本

时间:2014-01-24 06:44:31

标签: xslt xslt-2.0

我想以指定的格式转换下面的XML。我可以使用XSLT 2.0吗?

基本上,我想在一些元素中放置文本,并按特定顺序对新文本元素和现有子元素进行排序,因此我的xml序列化程序可以将输出xml序列化为适当的类属性。

输入XML:

<properties>
My Parent level text 1
<child1>  
text1 of first child <b> in bold</b>  
<childval>36-37</childval> 
text2 of child <i> in italic </i> 
</child1>
My Parent level text2 in <i>italic</i> also in <b>bold </b>
</properties>

预期输出XML:

<properties>
  <parenttext order="1">My Parent level text 1</parenttext>
  <child1 order="2">  
    <childtext childorder="1" > text1 of first child <b> in bold</b>     
    </childtext>
    <childval childorder="2">36-37</childval> 
    <childtext childorder="3" >text2 of child <i> in italic </i>  
    </childtext>
  </child1>
  <parenttext order="3">My Parent level text2 in <i>italic</i> also in <b>bold </b> 
  </parenttext>
</properties>

1 个答案:

答案 0 :(得分:1)

这是一个令人讨厌的源结构,如果你可以我首先开始在源代码中进行更改......

您可以尝试这样的事情:

<?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:variable name="inlineElements" select="'b','i'"/>

<xsl:template match="properties">
    <properties>
        <xsl:for-each-group select="node()" group-adjacent="self::text() or self::node()[name()=$inlineElements]">
            <xsl:choose>
                <xsl:when test="current-grouping-key()=true()">
                    <parenttext><xsl:copy-of select="current-group()"/></parenttext>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="."/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group> 
    </properties>
</xsl:template>

<xsl:template match="child1">
    <xsl:element name="{name()}">
        <xsl:for-each-group select="node()" group-adjacent="self::text() or self::node()[name()=$inlineElements]">
            <xsl:choose>
                <xsl:when test="current-grouping-key()=true()">
                    <childtext><xsl:copy-of select="current-group()"/></childtext>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="."/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:element>
</xsl:template>

<xsl:template match="childval">
    <xsl:copy>
        <xsl:value-of select="."/>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>

这会使您想要的输出减去您的订单属性。

group-adjacent将检查所有节点并将生成相同分组键的所有内容分组在一起,直到节点生成另一个分组键。因此,文本和内联节点将生成true,直到子节点到来,这将生成false等等......


之后,您可以使用第二个转换添加订单属性:

<?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" xmlns:epub="hkda" exclude-result-prefixes="xs"
version="2.0">

<!-- copy template -->
<xsl:template match="node() | @*">
    <xsl:copy>
        <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
</xsl:template>

<!-- match nodes which should have order nr -->
<xsl:template match="parrenttext | childtext | childval">
    <xsl:copy>
        <xsl:attribute name="orderno" select="position()"/>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>