2014-10-07 57 views
0

我搜索并接近找到一个解决方案,但这需要Stylesheet 2.0,我被困在1.0。多个记录/元素被分组以创建新的结构

这是样本XML我:

<root> 
<row>A1: Apples</row> 
<row>B1: Red</row> 
<row>C1: Reference text</row> 
<row>badly formatted text which belongs to row above</row> 
<row>and here.</row> 
<row>D1: ABC</row> 
<row>E1: 123</row> 
<row>A1: Oranges</row> 
<row>B1: Purple</row> 
<row>C1: More References</row> 
<row>with no identifier</row> 
<row>again and here.</row> 
<row>D1: DEF</row> 
<row>E1: 456</row> 
. 
. 

我希望它看起来像:

<root> 
<row> 
    <A1>Apples</A1> 
    <B1>Red</B1> 
    <C1>Reference text badly formatted text which belongs to row above and here.</C1> 
    <D1>ABC</D1> 
    <E1>123</E1> 
</row> 
<row> 
    <A1>Oranges</A1> 
    <B1>Purple</B1> 
    <C1>More Reference with no identifier again and here.</C1> 
    <D1>DEF</D1> 
    <E1>456</E1> 
</row> 
. 
. 

还有就是这个,我可以一个模式使用其他实用程序进行转换,但使用XSL 1.0很难。

我可以使用的元素中有标题,而参考文本字段在转换为XML时是多行的,它为每行创建了自己的行,但它始终位于C1和D1之间的相同位置。元素的实际名称,即不重要。

该行在E1之后应该分解。我认为我的例子很简单,但这种转变不是。我认为我自己甚至不是XML/XSL的初学者。我正在从头学习,然后我转向其他项目,然后不得不再次回来。 TIA。

更新:我遇到了略有不同的结构,还有一种情况,但我想要的结果是一样的:

<root> 
    <row> 
    <Field>A1: Apples</Field> 
    </row> 
<row> 
    <Field>B1: Red</Field> 
</row> 
<row> 
    <Field>C1: Reference text</Field> 
</row> 
<row> 
    <Field>badly formatted text which belongs to row above</Field> 
</row> 
<row> 
    <Field>and here.</Field> 
</row> 
<row> 
    <Field>D1: ABC</Field> 
</row> 
<row> 
    <Field>E1: 123</Field> 
</row> 
<row> 
    <Field>A1: Oranges</Field> 
</row> 
<row> 
    <Field>B1: Purple</Field> 
</row> 
<row> 
    <Field>C1: More References</Field> 
</row> 
<row> 
    <Field>with no identifier</Field> 
</row> 
<row> 
    <Field>again and here.</Field> 
</row> 
<row> 
    <Field>D1: DEF</Field> 
</row> 
<row> 
    <Field>E1: 456</Field> 
</row> 

我试图将一个身份变换,但似乎没有工作:

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

“*有这种模式*”你可以在描述这种模式更加明确?我看到每7行创建一个组 - 但在示例中这可能只是巧合。 – 2014-10-07 14:23:54

+0

是的,这是模式,而不是巧合。每个记录或组是7行。谢谢。 – 2014-10-08 15:23:21

回答

0

这看起来有点棘手,但我有一个似乎工作的解决方案。它允许在C1行之后有可变数量的行(不清楚它是否总是2行)。

该解决方案大量使用following-sibling轴,这可能非常低效,特别是对于大型输入文件。

你可以测试一下here

<xsl:template match="/root"> 
    <!-- Loop through every "A1" row --> 
    <xsl:for-each select="row[substring-before(text(), ':') = 'A1']"> 
     <!-- Add a <row> tag --> 
      <xsl:element name="row"> 
       <!-- Add each of the A1-E1 tags by finding the first following-sibling that matches before the colon --> 
       <xsl:apply-templates select="." /> 
       <xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'B1'][1]" /> 
       <xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'C1'][1]" /> 
       <xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'D1'][1]" /> 
       <xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'E1'][1]" /> 
      </xsl:element> 
     </xsl:for-each> 
    </xsl:template> 

    <!-- Process each row --> 
    <xsl:template match="/root/row"> 
     <!-- Create an element whose name is whatever is before the colon in the text --> 
     <xsl:element name="{substring-before(text(), ':')}"> 
      <!-- Output everything after the colon --> 
      <xsl:value-of select="normalize-space(substring-after(text(), ':'))" /> 
      <!-- Special treatment for the C1 node --> 
      <xsl:if test="substring-before(text(), ':') = 'C1'"> 
       <!-- Count how many A1 nodes exist after this node --> 
       <xsl:variable name="remainingA1nodes" select="count(following-sibling::*[substring-before(text(), ':') = 'A1'])" /> 
       <!-- Loop through all following-siblings that don't have a colon at position 3, and still have the same number of following A1 rows as this one does --> 
       <xsl:for-each select="following-sibling::*[substring(text(), 3, 1) != ':'][count(following-sibling::*[substring-before(text(), ':') = 'A1']) = $remainingA1nodes]"> 
        <xsl:text> </xsl:text> 
        <xsl:value-of select="." /> 
       </xsl:for-each> 
      </xsl:if> 
     </xsl:element> 
    </xsl:template> 
+0

是啊哇,感谢您花时间做这件事,我会尽快与其他一些数据集一起进行测试,这些数据集与我的示例类似。 – 2014-10-08 15:23:58

+0

@ user2300736,如果解决方案适用于您,请单击解决方案左侧的复选标记以接受该解决方案。 – GentlePurpleRain 2014-10-08 15:45:20

+0

完成。这两个解决方案的工作,我可以使用取决于我得到的数据。感谢帮助!谢谢, – 2014-10-08 23:12:09

0

每个记录或组为7行。

那么,为什么不这样做只是由数字:

XSLT 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" version="1.0" encoding="UTF-8" indent="yes"/> 

<xsl:template match="/root"> 
    <root> 
     <xsl:for-each select="row[position() mod 7 = 1]"> 
      <row> 
       <xsl:apply-templates select=". | following-sibling::row[position() &lt; 3] | following-sibling::row[4 &lt; position() and position() &lt; 7]"/> 
      </row> 
     </xsl:for-each> 
    </root> 
</xsl:template> 

<xsl:template match="row"> 
    <xsl:element name="{substring-before(., ': ')}"> 
     <xsl:value-of select="substring-after(., ': ')"/> 
    </xsl:element> 
</xsl:template> 

<xsl:template match="row[starts-with(., 'C1: ')]"> 
    <C1> 
     <xsl:value-of select="substring-after(., 'C1: ')"/> 
     <xsl:for-each select="following-sibling::row[position() &lt; 3]"> 
      <xsl:text> </xsl:text> 
      <xsl:value-of select="."/> 
     </xsl:for-each> 
    </C1> 
</xsl:template> 

</xsl:stylesheet> 
+0

是的,我也可以做到这一点,这将在很多情况下派上用场。感谢您的帮助! – 2014-10-08 23:12:43

+0

我试图更多地理解位置函数:你如何解释你写的这一行: 2014-10-12 23:50:15

+0

这意味着选择当前节点及其后续节点#1,#2,#5和#6。注意position()是依赖于上下文的。在当前节点(A1)的上下文中,第一个下一个兄弟节点是B1。 – 2014-10-13 05:14:07