2012-06-27 50 views
5

EDIT - Tôi đã tìm ra giải pháp cho vấn đề của mình và đăng Q & A here.Loại trừ các nút con nhất định khi cấu trúc dữ liệu không xác định

Tôi đang tìm cách xử lý XML tuân theo tiêu chuẩn EAD của Thư viện Quốc hội (được tìm thấy here). Thật không may, tiêu chuẩn rất lỏng lẻo về cấu trúc của XML.

Ví dụ thẻ <bioghist> có thể tồn tại trong thẻ <archdesc>, hoặc trong một thẻ <descgrp>, hoặc lồng trong một <bioghist> thẻ, hoặc sự kết hợp của các bên trên, hoặc có thể được bỏ qua hoàn toàn. Tôi đã tìm thấy nó rất khó để chọn chỉ là thẻ bioghist tôi đang tìm kiếm mà không cần chọn những người khác.

Dưới đây là một vài khả năng tài liệu EAD XML khác nhau XSLT tôi có thể phải xử lý:

dụ đầu tiên

<ead> 
<eadheader> 
    <archdesc> 
     <bioghist>one</bioghist> 
     <dsc> 
      <c01> 
       <descgrp> 
        <bioghist>two</bioghist> 
       </descgrp> 
       <c02> 
        <descgrp> 
         <bioghist> 
          <bioghist>three</bioghist> 
         </bioghist> 
        </descgrp> 
       </c02> 
      </c01> 
     </dsc> 
    </archdesc> 
</eadheader> 
</ead> 

Thứ hai ví dụ

<ead> 
<eadheader> 
    <archdesc> 
     <descgrp> 
      <bioghist> 
       <bioghist>one</bioghist> 
      </bioghist> 
     </descgrp> 
     <dsc> 
      <c01> 
       <c02> 
        <descgrp> 
         <bioghist>three</bioghist> 
        </descgrp> 
       </c02> 
       <bioghist>two</bioghist> 
      </c01> 
     </dsc> 
    </archdesc> 
</eadheader> 
</ead> 

Thứ ba ví dụ

<ead> 
<eadheader> 
    <archdesc> 
     <descgrp> 
      <bioghist>one</bioghist> 
     </descgrp> 
     <dsc> 
      <c01> 
       <c02> 
        <bioghist>three</bioghist> 
       </c02> 
      </c01> 
     </dsc> 
    </archdesc> 
</eadheader> 
</ead> 

Như bạn có thể thấy, tệp XML EAD có thể có thẻ <bioghist> ở hầu hết mọi nơi. Sản lượng thực tế tôi cho là sản xuất quá phức tạp để đăng ở đây. Một ví dụ đơn giản của đầu ra cho ba EAD ví dụ trên có thể như:

Output ví dụ đầu tiên

<records> 
<primary_record> 
    <biography_history>first</biography_history> 
</primary_record> 
<child_record> 
    <biography_history>second</biography_history> 
</child_record> 
<granchild_record> 
    <biography_history>third</biography_history> 
</granchild_record> 
</records> 

Output ví dụ thứ hai

<records> 
<primary_record> 
    <biography_history>first</biography_history> 
</primary_record> 
<child_record> 
    <biography_history>second</biography_history> 
</child_record> 
<granchild_record> 
    <biography_history>third</biography_history> 
</granchild_record> 
</records> 

Output cho thứ ba ví dụ

<records> 
<primary_record> 
    <biography_history>first</biography_history> 
</primary_record> 
<child_record> 
    <biography_history></biography_history> 
</child_record> 
<granchild_record> 
    <biography_history>third</biography_history> 
</granchild_record> 
</records> 

Nếu tôi muốn lấy giá trị "bioghist" đầu tiên và đặt vào số <primary_record>, tôi không thể chỉ đơn giản là <xsl:apply-templates select="/ead/eadheader/archdesc/bioghist", vì thẻ đó có thể không phải là hậu duệ trực tiếp của thẻ <archdesc>. Nó có thể được bao bọc bởi <descgrp> hoặc <bioghist> hoặc kết hợp chúng. Và tôi không thể select="//bioghist", vì điều đó sẽ kéo tất cả các thẻ <bioghist>. Tôi thậm chí không thể select="//bioghist[1]" vì có thể không thực sự là một thẻ <bioghist> ở đó và sau đó tôi sẽ kéo giá trị bên dưới <c01>, đây là "Thứ hai" và sẽ được xử lý sau.

Đây đã là một bài đăng dài, nhưng một nếp nhăn khác là có thể có số lượng không giới hạn các nút <cxx>, lồng nhau đến mười hai cấp độ sâu. Tôi hiện đang xử lý chúng một cách đệ quy. Tôi đã thử lưu nút mà tôi hiện đang xử lý (ví dụ: <c01>) dưới dạng biến được gọi là 'RN', sau đó chạy <xsl:apply-templates select=".//bioghist [name(..)=name($RN) or name(../..)=name($RN)]">.Điều này làm việc cho một số dạng EAD, trong đó thẻ <bioghist> không lồng nhau quá sâu, nhưng nó sẽ thất bại nếu nó phải xử lý tệp EAD được tạo bởi người yêu thẻ gói trong các thẻ khác (điều này hoàn toàn phù hợp với Tiêu chuẩn EAD).

Những gì tôi muốn yêu là cách nọ cách kia nói

  • Nhận bất kỳ thẻ <bioghist> bất cứ nơi nào bên dưới nút hiện tại nhưng
  • không đào sâu hơn nếu bạn nhấn một <c??> thẻ

tôi hy vọng rằng tôi đã làm cho tình hình rõ ràng. Xin vui lòng cho tôi biết nếu tôi đã để lại bất cứ điều gì mơ hồ. Bất kỳ hỗ trợ nào bạn có thể cung cấp sẽ được đánh giá cao. Cảm ơn.

Trả lời

0

Tôi đã tự mình tìm ra giải pháp và đăng tại giải pháp này Q&A vì giải pháp này khá cụ thể đối với một tiêu chuẩn XML nhất định và dường như nằm ngoài phạm vi của câu hỏi này. Nếu mọi người cảm thấy tốt nhất nên đăng nó ở đây, tôi có thể cập nhật câu trả lời này bằng một bản sao.

2

Do yêu cầu khá mơ hồ, mọi câu trả lời chỉ phản ánh phỏng đoán tác giả của nó.

Dưới đây là của tôi:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:my="my:my" exclude-result-prefixes="my"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<my:names> 
    <n>primary_record</n> 
    <n>child_record</n> 
    <n>grandchild_record</n> 
</my:names> 

<xsl:variable name="vNames" select="document('')/*/my:names/*"/> 

<xsl:template match="/"> 
    <xsl:apply-templates select= 
    "//bioghist[following-sibling::node()[1] 
           [self::descgrp] 
       ]"/> 
</xsl:template> 

<xsl:template match="bioghist"> 
    <xsl:variable name="vPos" select="position()"/> 

    <xsl:element name="{$vNames[position() = $vPos]}"> 
    <xsl:value-of select="."/> 
    </xsl:element> 
</xsl:template> 

<xsl:template match="text()"/> 
</xsl:stylesheet> 

Khi chuyển đổi này được áp dụng trên các tài liệu XML cung cấp:

<ead> 
    <eadheader> 
     <archdesc> 
      <bioghist>first</bioghist> 
      <descgrp> 
       <bioghist>first</bioghist> 
       <bioghist> 
        <bioghist>first</bioghist></bioghist> 
      </descgrp> 
      <dsc> 
       <c01> 
        <bioghist>second</bioghist> 
        <descgrp> 
         <bioghist>second</bioghist> 
         <bioghist> 
          <bioghist>second</bioghist></bioghist> 
        </descgrp> 
        <c02> 
         <bioghist>third</bioghist> 
         <descgrp> 
          <bioghist>third</bioghist> 
          <bioghist> 
           <bioghist>third</bioghist></bioghist> 
         </descgrp> 
        </c02> 
       </c01> 
      </dsc> 
     </archdesc> 
    </eadheader> 
</ead> 

kết quả mong muốn được sản xuất:

<primary_record>first</primary_record> 
<child_record>second</child_record> 
<grandchild_record>third</grandchild_record> 
+0

Tôi xin lỗi vì các yêu cầu không rõ ràng. Một tài liệu EAD xml thích hợp chứa 30 hoặc 40 phần thông tin khác nhau, mỗi thông tin có thẻ riêng. Đầu ra tôi tạo ra sử dụng tất cả các thẻ khác nhau, và tôi đã tìm ra đầu vào/đầu ra đơn giản có thể là tốt nhất để truyền đạt bản chất của vấn đề. Xslt của bạn cao hơn một chút so với những gì tôi quen thuộc, nhưng tôi nghĩ rằng tôi đã tìm ra một vài phần. Mẫu phù hợp với bioghist sẽ chỉ được chạy ba lần, mỗi lần tạo một phần tử có tên khác, đúng không? Bây giờ câu hỏi của tôi là tại sao mẫu chỉ chạy 3 lần. – aarondev

+0

@aarondev: Câu trả lời rất đơn giản: chỉ có ba phần tử trong tài liệu XML được cung cấp phù hợp với mẫu. Mẫu khớp với bất kỳ 'bioghist' nào trong tài liệu XML, mà nút anh chị em sau đây đầu tiên của nó là một phần tử' descgrp' - có chính xác ba phần tử bioghist' trong tài liệu XML được cung cấp. –

+0

Vì vậy, các anh chị em sau đây khớp với tất cả các nút anh chị em. Và sau đó bạn đang chọn chỉ là người đầu tiên của những người anh em với [1], phải không? Tự :: descgrp bit vẫn còn làm tôi bối rối. Đó có phải là nút hiện tại của nút descgrp không? – aarondev

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