2010-10-18 34 views
8

Tôi có một số XML với các yếu tố <ListItem> và tôi muốn bao gồm bất kỳ lần chạy liên tiếp nào với các yếu tố <List>. Vì vậy, nguồn XML sẽ giống như thế này:Làm cách nào để bọc một nhóm các phần tử liền kề bằng XSLT?

<Section> 
    <Head>Heading</Head> 
    <Para>Blah</Para> 
    <ListItem>item 1</ListItem> 
    <ListItem>item 2</ListItem> 
    <ListItem>item 3</ListItem> 
    <ListItem>item 4</ListItem> 
    <Para>Something else</Para> 
</Section> 

Và tôi muốn chuyển nó sang một cái gì đó như thế này:

<Section> 
    <Head>Heading</Head> 
    <Para>Blah</Para> 
    <List> 
    <ListItem>item 1</ListItem> 
    <ListItem>item 2</ListItem> 
    <ListItem>item 3</ListItem> 
    <ListItem>item 4</ListItem> 
    </List> 
    <Para>Something else</Para> 
</Section> 

sử dụng XSLT. Tôi chắc chắn nó là hiển nhiên nhưng tôi không thể làm việc nó ra vào lúc này vào buổi tối. Cảm ơn!


Edit: này có thể được bỏ qua một cách an toàn bởi hầu hết mọi người.

XML này:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<Root> 
    <Story> 
    <Section id="preface"> 
     <ChapterTitle>Redacted</ChapterTitle> 
     <HeadA>Redacted</HeadA> 
     <Body>Redacted</Body> 
     <BulletListItem>Item1</BulletListItem> 
     <BulletListItem>Item2</BulletListItem> 
     <BulletListItem>Item3</BulletListItem> 
     <BulletListItem>Item4</BulletListItem> 
     <HeadA>Redacted</HeadA> 
     <Body>Redacted</Body> 
     <HeadA>Redacted</HeadA> 
     <Body>Redacted</Body> 
     <Body>Redacted<Italic>REDACTED</Italic>Redacted</Body> 
     <BulletListItem>Second list Item1</BulletListItem> 
     <BulletListItem>Second list Item2</BulletListItem> 
     <BulletListItem>Second list Item3</BulletListItem> 
     <BulletListItem>Second list Item4</BulletListItem> 
     <Body>Redacted</Body> 
    </Section> 
    </Story> 
</Root> 

Với XSL này:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:key name="kFollowing" match="BulletListItem[preceding-sibling::*[1][self::BulletListItem]]" 
    use="generate-id(preceding-sibling::BulletListItem 
     [not(preceding-sibling::*[1][self::BulletListItem])])"/> 

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

<xsl:template match="BulletListItem 
     [not(preceding-sibling::*[1][self::BulletListItem])]"> 
    <BulletList> 
    <xsl:call-template name="identity"/> 
    <xsl:apply-templates mode="copy" select="key('kFollowing', generate-id())"/> 
    </BulletList> 
</xsl:template> 

<xsl:template match="BulletListItem[preceding-sibling::*[1][self::BulletListItem]]"/> 

<xsl:template match="BulletListItem" mode="copy"> 
    <xsl:call-template name="identity"/> 
</xsl:template> 
</xsl:stylesheet> 

Khi xử lý với Ruby REXML và XML/XSLT tạo ra XML này (đầu ra prettyprint):

<Root> 
    <Story> 
    <Section id='preface'> 
     <ChapterTitle> 
     Redacted 
     </ChapterTitle> 
     <HeadA> 
     Redacted 
     </HeadA> 
     <Body> 
     Redacted 
     </Body> 
     <BulletList> 
     <BulletListItem> 
      Item1 
     </BulletListItem> 
     <BulletListItem> 
      Item2 
     </BulletListItem> 
     <BulletListItem> 
      Item3 
     </BulletListItem> 
     <BulletListItem> 
      Item4 
     </BulletListItem> 
     <BulletListItem> 
      Second list Item2 
     </BulletListItem> 
     <BulletListItem> 
      Second list Item3 
     </BulletListItem> 
     <BulletListItem> 
      Second list Item4 
     </BulletListItem> 
     </BulletList> 
     <HeadA> 
     Redacted 
     </HeadA> 
     <Body> 
     Redacted 
     </Body> 
     <HeadA> 
     Redacted 
     </HeadA> 
     <Body> 
     Redacted 
     </Body> 
     <Body> 
     Redacted 
     <Italic> 
      REDACTED 
     </Italic> 
     Redacted 
     </Body> 
     <BulletList> 
     <BulletListItem> 
      Second list Item1 
     </BulletListItem> 
     </BulletList> 
     <Body> 
     Redacted 
     </Body> 
    </Section> 
    </Story> 
</Root> 

Bạn sẽ thấy rằng hai danh sách bị kẹt lại với nhau và bit ở giữa bị mất. Không chắc chắn nếu đây là một lỗi trong thư viện Ruby hoặc trong XSLT của bạn.

+0

Tôi quá lai cho tìm kiếm trùng lặp ... Nếu ai đó đăng các liên kết tôi sẽ xóa câu trả lời. –

+0

Câu hỏi hay, +1. Xem câu trả lời của tôi cho một giải pháp dựa trên khóa hiệu quả. –

+0

Tôi lấy lại những gì tôi nói về nó là hiển nhiên: P Tôi thực sự cần phải học XSLT đúng cách ... – Skilldrick

Trả lời

4

kiểu này:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:strip-space elements="*"/> 
    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()[1]"/> 
     </xsl:copy> 
     <xsl:apply-templates select="following-sibling::node()[1]"/> 
    </xsl:template> 
    <xsl:template match="ListItem"> 
     <List> 
      <xsl:call-template name="ListItem"/> 
     </List> 
     <xsl:apply-templates select="following-sibling::node() 
             [not(self::ListItem)][1]"/> 
    </xsl:template> 
    <xsl:template match="ListItem[preceding-sibling::node()[1] 
               /self::ListItem]" 
        name="ListItem"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()[1]"/> 
     </xsl:copy> 
     <xsl:apply-templates select="following-sibling::node()[1] 
               /self::ListItem"/> 
    </xsl:template> 
</xsl:stylesheet> 

Output:

<Section> 
    <Head>Heading</Head> 
    <Para>Blah</Para> 
    <List> 
     <ListItem>item 1</ListItem> 
     <ListItem>item 2</ListItem> 
     <ListItem>item 3</ListItem> 
     <ListItem>item 4</ListItem> 
    </List> 
    <Para>Something else</Para> 
</Section> 

Sửa 3: Sử dụng strip-space cho những gì nó được.

+0

Xin lỗi tôi không thể chọn cả hai! – Skilldrick

+0

@Alejandro - lạ ... Khi tôi chạy biểu định kiểu này trên đầu vào đã cho, tôi nhận được một cái gì đó rất khác nhau. Cụ thể, nút 'select =" sau-sibling :: node() [1] [tự :: ListItem] "' của bạn bỏ qua ListItem sau bởi vì nút anh chị em sau đây đầu tiên là một nút văn bản khoảng trắng. Tuy nhiên, tôi thấy không có lý do (http://www.w3.org/TR/xslt#strip) tại sao nút đó không bị tước. Tôi bối rối?! – LarsH

+0

@Alejandro: PS điều này xảy ra ở Saxon 6.5.5 trong Oxy. Không có thuộc tính xml: space = "preserve" ở bất kỳ đâu. – LarsH

5

chuyển đổi này:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:key name="kFollowing" match="ListItem[preceding-sibling::*[1][self::ListItem]]" 
    use="generate-id(preceding-sibling::ListItem 
     [not(preceding-sibling::*[1][self::ListItem])][1])"/> 

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

<xsl:template match="ListItem 
     [not(preceding-sibling::*[1][self::ListItem])]"> 
    <List> 
    <xsl:call-template name="identity"/> 
    <xsl:apply-templates mode="copy" select="key('kFollowing', generate-id())"/> 
    </List> 
</xsl:template> 

<xsl:template match="ListItem[preceding-sibling::*[1][self::ListItem]]"/> 

<xsl:template match="ListItem" mode="copy"> 
    <xsl:call-template name="identity"/> 
</xsl:template> 
</xsl:stylesheet> 

khi áp dụng trên tài liệu XML cung cấp:

<Section> 
    <Head>Heading</Head> 
    <Para>Blah</Para> 
    <ListItem>item 1</ListItem> 
    <ListItem>item 2</ListItem> 
    <ListItem>item 3</ListItem> 
    <ListItem>item 4</ListItem> 
    <Para>Something else</Para> 
</Section> 

tạo ra kết quả mong muốn:

<Section> 
    <Head>Heading</Head> 
    <Para>Blah</Para> 
    <List> 
     <ListItem>item 1</ListItem> 
     <ListItem>item 2</ListItem> 
     <ListItem>item 3</ListItem> 
     <ListItem>item 4</ListItem> 
    </List> 
    <Para>Something else</Para> 
</Section> 
+0

@Dimitre: +1 Câu trả lời hay. Tôi sẽ thêm loại giải pháp này khi tôi nhìn thấy bạn. –

+0

Cảm ơn, điều đó đã hoạt động hoàn hảo! – Skilldrick

+0

@Dimitre - Tôi đã phát hiện thấy một lỗi với điều này. Tôi đã sao chép các trường hợp trong câu hỏi của tôi. – Skilldrick

Các vấn đề liên quan