XSD - làm thế nào để cho phép các phần tử theo thứ tự bất kỳ với số lần bất kỳ?


109

Tôi đang cố gắng tạo XSD và cố gắng viết định nghĩa với yêu cầu sau:

  • Cho phép phần tử con được chỉ định xuất hiện bất kỳ số lần nào (0 đến không bị ràng buộc)
  • Cho phép các phần tử con theo bất kỳ thứ tự nào

Tôi đã xem xét xung quanh và tìm thấy các giải pháp khác nhau như sau :

<xs:element name="foo">
  <xsl:complexType>
    <xs:choice minOccurs="0" maxOccurs="unbounded">
      <xs:element name="child1" type="xs:int"/>
      <xs:element name="child2" type="xs:string"/>
    </xs:choice>
  </xs:complexType>
</xs:element>

Nhưng từ những gì tôi hiểu xs: choice vẫn chỉ cho phép lựa chọn phần tử duy nhất. Do đó, việc đặt MaxOccurs thành không bị ràng buộc như vậy chỉ có nghĩa là "bất kỳ một" phần tử con nào có thể xuất hiện nhiều lần. Nó thật sự đúng?

Nếu giải pháp trên không chính xác, làm thế nào tôi có thể đạt được những gì tôi đã nêu ở trên trong yêu cầu của mình?

CHỈNH SỬA : Nếu yêu cầu là như sau thì sao?

  • Phần tử child1 child2 có thể xuất hiện bất kỳ số lần nào (0 đến không bị ràng buộc)
  • Các yếu tố theo thứ tự bất kỳ
  • Các phần tử child3 và child4 sẽ xuất hiện đúng một lần.

Ví dụ: xml này hợp lệ:

<foo>
<child1> value </child1>
<child1> value </child1>
<child3> value </child3>
<child2> value </child2>
<child4> value </child4>
<child1> value </child1>
</foo>

nhưng đây không phải là (thiếu con3)

<foo>
<child1> value </child1>
<child1> value </child1>
<child2> value </child2>
<child4> value </child4>
<child1> value </child1>
</foo>

Câu trả lời:


61

Trong lược đồ mà bạn có trong câu hỏi của mình, child1hoặc child2có thể xuất hiện theo bất kỳ thứ tự nào, bất kỳ số lần nào. Vì vậy, điều này nghe giống như những gì bạn đang tìm kiếm.

Chỉnh sửa: nếu bạn chỉ muốn một trong số chúng xuất hiện không giới hạn số lần, thay vào đó, phần không bị ràng buộc sẽ phải đi vào các phần tử:

Chỉnh sửa: Loại cố định trong XML.

Chỉnh sửa: O viết hoa trong maxOccurs

<xs:element name="foo">
   <xs:complexType>
     <xs:choice maxOccurs="unbounded">
       <xs:element name="child1" type="xs:int" maxOccurs="unbounded"/>
       <xs:element name="child2" type="xs:string" maxOccurs="unbounded"/>
     </xs:choice>
   </xs:complexType>
</xs:element>

về cơ bản là có, tôi đang tìm các phần tử child1, child2 xuất hiện theo thứ tự bất kỳ, số lần bất kỳ .. câu trả lời bạn cung cấp ở đây chỉ hoạt động cho một phần tử, phải không? hoặc điều này cũng giải quyết yêu cầu của tôi?
jvtech

Lược đồ trong câu hỏi của bạn đáp ứng yêu cầu của bạn; lược đồ thay thế trong câu trả lời của tôi dành cho một phần tử duy nhất. Hy vọng rằng nó sáng tỏ! :)
xcut

@Pavel, @xcut, Cảm ơn bạn đã làm rõ, xem yêu cầu đã chỉnh sửa .. bạn có suy nghĩ gì không?
jvtech 19/02/10

2
jvtech: bạn không thể đáp ứng yêu cầu đã chỉnh sửa đó với lược đồ XML; cách duy nhất để đạt được nó sẽ là nếu child3 và child4 chỉ có thể xuất hiện ở phần cuối. Trong trường hợp đó, bạn cần một chuỗi chứa một lựa chọn và sau đó là hai phần tử.
xcut

1
@ Daij-Djan Tôi cũng thấy rằng nó không hoạt động. Hãy thử thêm maxOccurs = "unbound" vào phần tử lựa chọn để cho phép nhiều phần tử con.
MikeD

107

Công thức thay thế của câu hỏi được thêm vào trong bản chỉnh sửa sau này dường như vẫn chưa được trả lời: làm thế nào để chỉ định rằng trong số các phần tử con, phải có một phần tử được đặt tên child3, một phần tử được đặt tên child4và bất kỳ số nào có tên child1hoặc child2, không có ràng buộc về thứ tự trong mà những đứa trẻ xuất hiện.

Đây là một ngôn ngữ thông thường có thể xác định một cách dễ dàng và mô hình nội dung bạn cần là đồng cấu với một biểu thức chính quy xác định tập hợp các chuỗi trong đó các chữ số '3' và '4' mỗi xuất hiện đúng một lần và các chữ số '1' và '2 'xảy ra bất kỳ số lần nào. Nếu không rõ ràng về cách viết điều này, có thể hữu ích khi nghĩ về loại máy trạng thái hữu hạn mà bạn sẽ xây dựng để nhận ra một ngôn ngữ như vậy. Nó sẽ có ít nhất bốn trạng thái riêng biệt:

  • trạng thái ban đầu mà cả '3' và '4' đều không được nhìn thấy
  • trạng thái trung gian trong đó '3' đã được nhìn thấy nhưng không phải '4'
  • một trạng thái trung gian trong đó '4' đã được nhìn thấy nhưng không phải là '3'
  • trạng thái cuối cùng trong đó cả '3' và '4' đã được nhìn thấy

Cho dù ô tự động ở trạng thái nào, '1' và '2' có thể được đọc; chúng không thay đổi trạng thái của máy. Ở trạng thái ban đầu, "3" hoặc "4" cũng sẽ được chấp nhận; ở các trạng thái trung gian, chỉ chấp nhận '4' hoặc '3'; ở trạng thái cuối cùng, cả '3' và '4' đều không được chấp nhận. Cấu trúc của biểu thức chính quy dễ hiểu nhất nếu trước tiên chúng ta xác định một regex cho tập hợp con của ngôn ngữ của chúng ta, trong đó chỉ có '3' và '4' xảy ra:

(34)|(43)

Để cho phép '1' hoặc '2' xuất hiện bất kỳ số lần nào tại một vị trí nhất định, chúng tôi có thể chèn (1|2)*(hoặc [12]*nếu ngôn ngữ regex của chúng tôi chấp nhận ký hiệu đó). Chèn biểu thức này ở tất cả các vị trí có sẵn, chúng tôi nhận được

(1|2)*((3(1|2)*4)|(4(1|2)*3))(1|2)*

Chuyển nó thành một mô hình nội dung rất đơn giản. Cấu trúc cơ bản tương đương với regex (34)|(43):

<xsd:complexType name="paul0">
  <xsd:choice>
    <xsd:sequence>
      <xsd:element ref="child3"/>
      <xsd:element ref="child4"/>
    </xsd:sequence>
    <xsd:sequence>
      <xsd:element ref="child4"/>
      <xsd:element ref="child3"/>
    </xsd:sequence>
  </xsd:choice>
</xsd:complexType>

Chèn một lựa chọn không hoặc nhiều hơn child1child2rất đơn giản:

<xsd:complexType name="paul1">
  <xsd:sequence>
    <xsd:choice minOccurs="0" maxOccurs="unbounded">
      <xsd:element ref="child1"/>
      <xsd:element ref="child2"/>
    </xsd:choice>      
    <xsd:choice>
      <xsd:sequence>
        <xsd:element ref="child3"/>
        <xsd:choice minOccurs="0" maxOccurs="unbounded">
          <xsd:element ref="child1"/>
          <xsd:element ref="child2"/>
        </xsd:choice>      
        <xsd:element ref="child4"/>
      </xsd:sequence>
      <xsd:sequence>
        <xsd:element ref="child4"/>
        <xsd:choice minOccurs="0" maxOccurs="unbounded">
          <xsd:element ref="child1"/>
          <xsd:element ref="child2"/>
        </xsd:choice>      
        <xsd:element ref="child3"/>
      </xsd:sequence>
    </xsd:choice>
    <xsd:choice minOccurs="0" maxOccurs="unbounded">
      <xsd:element ref="child1"/>
      <xsd:element ref="child2"/>
    </xsd:choice>      
  </xsd:sequence>
</xsd:complexType>

Nếu chúng ta muốn giảm thiểu khối lượng lớn một chút, chúng ta có thể xác định một nhóm được đặt tên cho các lựa chọn lặp lại child1child2:

<xsd:group name="onetwo">
  <xsd:choice>
    <xsd:element ref="child1"/>
    <xsd:element ref="child2"/>
  </xsd:choice>   
</xsd:group>

<xsd:complexType name="paul2">
  <xsd:sequence>
    <xsd:group ref="onetwo" minOccurs="0" maxOccurs="unbounded"/>
    <xsd:choice>
      <xsd:sequence>
        <xsd:element ref="child3"/>
        <xsd:group ref="onetwo" minOccurs="0" maxOccurs="unbounded"/>
        <xsd:element ref="child4"/>
      </xsd:sequence>
      <xsd:sequence>
        <xsd:element ref="child4"/>
        <xsd:group ref="onetwo" minOccurs="0" maxOccurs="unbounded"/>
        <xsd:element ref="child3"/>
      </xsd:sequence>
    </xsd:choice>  
    <xsd:group ref="onetwo" minOccurs="0" maxOccurs="unbounded"/>
  </xsd:sequence>
</xsd:complexType>

Trong XSD 1.1, một số ràng buộc về allnhóm đã được dỡ bỏ, vì vậy có thể xác định mô hình nội dung này một cách ngắn gọn hơn:

<xsd:complexType name="paul3">
  <xsd:all>
    <xsd:element ref="child1" minOccurs="0" maxOccurs="unbounded"/>
    <xsd:element ref="child2" minOccurs="0" maxOccurs="unbounded"/>
    <xsd:element ref="child3"/>
    <xsd:element ref="child4"/>      
  </xsd:all>
</xsd:complexType>

Nhưng như có thể thấy từ các ví dụ được đưa ra trước đó, những thay đổi này đối với- allnhóm trên thực tế không làm thay đổi sức mạnh biểu đạt của ngôn ngữ; chúng chỉ làm cho định nghĩa của một số loại ngôn ngữ ngắn gọn hơn.


3
Tôi thích XSD 1.0 xs: tất cả đều thay thế.
TWiStErRob

8
+1. Đây là một câu trả lời xuất sắc và nó xứng đáng được nhiều lượt ủng hộ hơn.
Christoffer Lette

1
Câu trả lời chính xác ! Tôi thực sự thích những lời giải thích như thế này. Nó tiết lộ tất cả logic và lý do đằng sau việc đạt được mục tiêu. Bây giờ tôi không chỉ biết làm thế nào để giải quyết vấn đề này, nhưng tôi đã học được một cách tiếp cận mới để giải quyết các vấn đề tương tự. Giải thích điều này bằng cách sử dụng tự động hóa trạng thái hữu hạn là một ý tưởng rất hay.
egelev

3
Michael, bạn nói "những thay đổi này đối với tất cả các nhóm trên thực tế không làm thay đổi sức mạnh biểu đạt của ngôn ngữ; chúng chỉ làm cho định nghĩa của một số loại ngôn ngữ ngắn gọn hơn". Nhưng nếu bạn khái quát vấn đề cho bất kỳ số phần tử con nào, một tập hợp con có thể xuất hiện một lần và một tập hợp con khác có thể xuất hiện bất kỳ số lần nào, thì giải pháp XSD 1.0 sẽ dẫn đến một sự bùng nổ tổ hợp, phải không? Trong khi giải pháp XSD 1.1 sẽ vẫn sạch.
ebruchez

1
ebruchez, có - khả năng diễn đạt , như tôi đã sử dụng thuật ngữ, là không giống như tính cô đọng , chặt , terseness , hoặc quản lý . Quyền lực biểu đạt chỉ hỏi "Chủ nghĩa hình thức này có thể định nghĩa ngôn ngữ này không?" Nó không hỏi về kích thước của ngữ pháp, hoặc về việc liệu một số đường cú pháp có làm cho nó nhỏ hơn hay không. Sự bùng nổ tổ hợp mà bạn đề cập có nghĩa là việc xử lý các tập hợp phần tử lớn mà không có XSD 1.1 thay đổi thành tất cả các nhóm trở nên rất khó chịu rất nhanh (và đối với n lớn có thể làm cạn bộ nhớ). Nó không có nghĩa là chúng trở nên bất khả thi về nguyên tắc.
CM Sperberg-McQueen

49

Đây là những gì cuối cùng đã làm việc cho tôi:

<xsd:element name="bar">
  <xsd:complexType>
    <xsd:sequence>
      <!--  Permit any of these tags in any order in any number     -->
      <xsd:choice minOccurs="0" maxOccurs="unbounded">
        <xsd:element name="child1" type="xsd:string" />
        <xsd:element name="child2" type="xsd:string" />
        <xsd:element name="child3" type="xsd:string" />
      </xsd:choice>
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>

5
Trên thực tế các trick là để sử dụng xsd: sự lựa chọn với các quantifiers <xsd: minOccurs lựa chọn = "0" maxOccurs = "vô biên">
TiVo

6
Tôi nghĩ rằng điều đáng chỉ ra là ví dụ trên hoạt động ngay cả khi không có phần tử trình tự bao quanh phần tử lựa chọn.

9

Nhưng từ những gì tôi hiểu xs: choice vẫn chỉ cho phép lựa chọn phần tử duy nhất. Do đó, việc đặt MaxOccurs thành không bị ràng buộc như vậy chỉ có nghĩa là "bất kỳ một" phần tử con nào có thể xuất hiện nhiều lần. Nó thật sự đúng?

Không. Sự lựa chọn xảy ra riêng lẻ cho mỗi "sự lặp lại" của xs:choiceđiều đó xảy ra do maxOccurs="unbounded". Do đó, mã mà bạn đã đăng là chính xác và sẽ thực sự làm những gì bạn muốn như đã viết.


Nhận xét của bạn với câu trả lời do @Alan cung cấp giải thích tất cả một cách độc đáo.
bor

3

Bạn sẽ thấy rằng lược đồ sau đây cho phép những gì bạn đã đề xuất.

  <xs:element name="foo">
    <xs:complexType>
      <xs:sequence minOccurs="0" maxOccurs="unbounded">
        <xs:choice>
          <xs:element maxOccurs="unbounded" name="child1" type="xs:unsignedByte" />
          <xs:element maxOccurs="unbounded" name="child2" type="xs:string" />
        </xs:choice>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

Điều này sẽ cho phép bạn tạo một tệp như:

<?xml version="1.0" encoding="utf-8" ?>
<foo>
  <child1>2</child1>
  <child1>3</child1>
  <child2>test</child2>
  <child2>another-test</child2>
</foo>

Có vẻ phù hợp với câu hỏi của bạn.


minOccursmaxOccursđược giới hạn ở 1 cho trẻ em của xs:all.
Pavel Minaev

Pavel: Cảm ơn ... Tôi phát hiện ra điều này sau khi double-kiểm tra bài của tôi và sau đó sửa nó để loại bỏ các xs: all
Steven_W

1

Nếu không có cách nào ở trên hoạt động, có thể bạn đang làm việc trên EDI trasaction, nơi bạn cần xác thực kết quả của mình dựa trên lược đồ HIPPA hoặc bất kỳ xsd phức tạp nào khác cho vấn đề đó. Yêu cầu là, giả sử có 8 phân đoạn REF và bất kỳ phân đoạn nào trong số chúng phải xuất hiện theo bất kỳ thứ tự nào và cũng không phải tất cả đều được yêu cầu, có nghĩa là bạn có thể có chúng theo thứ tự REF thứ nhất, REF thứ 3, REF thứ 2, REF thứ 9. Trong tình huống mặc định, nhận EDI sẽ không thành công, do loại phức tạp mặc định là

<xs:sequence>
  <xs:element.../>
</xs:sequence>

Tình hình thậm chí còn phức tạp khi bạn gọi phần tử của mình bằng cách gọi lại và sau đó phần tử đó ở vị trí ban đầu tự nó khá phức tạp. ví dụ:

<xs:element>
<xs:complexType>
<xs:sequence>
<element name="REF1"  ref= "REF1_Mycustomelment" minOccurs="0" maxOccurs="1">
<element name="REF2"  ref= "REF2_Mycustomelment" minOccurs="0" maxOccurs="1">
<element name="REF3"  ref= "REF3_Mycustomelment" minOccurs="0" maxOccurs="1">
</xs:sequence>
</xs:complexType>
</xs:element>

Giải pháp:

Ở đây chỉ cần thay thế "chuỗi" bằng "tất cả" hoặc sử dụng "lựa chọn" với kết hợp tối thiểu / tối đa sẽ không hoạt động!

Điều đầu tiên thay thế "xs:sequence" with "<xs:all>" Bây giờ, Bạn cần thực hiện một số thay đổi nơi bạn đang Tham chiếu phần tử từ đó, Chuyển đến:

<xs:annotation>
  <xs:appinfo>
    <b:recordinfo structure="delimited" field.........Biztalk/2003">

*** Bây giờ trong phân đoạn trên, hãy thêm điểm kích hoạt vào cuối cùng như sau trigger_field = "REF01 _... tên đầy đủ .." trigger_value = "38" Làm tương tự cho các phân đoạn REF khác, nơi giá trị kích hoạt sẽ khác như nói "18 "," XX "," YY ", v.v ... do đó thông tin hồ sơ của bạn bây giờ trông giống như sau:b:recordinfo structure="delimited" field.........Biztalk/2003" trigger_field="REF01_...complete name.." trigger_value="38">


Điều này sẽ làm cho mỗi phần tử là duy nhất, lý do là Tất cả các segements REF (ví dụ trên) có cùng cấu trúc như REF01, REF02, REF03. Và trong quá trình xác thực, việc xác nhận cấu trúc là ok nhưng nó không để các giá trị lặp lại vì nó cố gắng tìm kiếm các giá trị còn lại trong chính REF đầu tiên. Việc thêm các trình kích hoạt sẽ làm cho tất cả chúng trở nên duy nhất và chúng sẽ vượt qua theo bất kỳ thứ tự và trường hợp tình huống nào (như sử dụng 5 trên 9 chứ không phải tất cả 9/9).

Hy vọng nó sẽ giúp bạn, vì tôi đã dành gần 20 giờ cho việc này.

Chúc may mắn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.