2010-05-05 35 views
8

(Lưu ý:. Tôi không thể thay đổi cấu trúc của XML Tôi nhận tôi chỉ có thể thay đổi thế nào tôi xác nhận nó.)Lược đồ XML: Tôi có thể yêu cầu một số giá trị của thuộc tính nhưng vẫn cho phép các giá trị khác không?

Hãy nói rằng tôi có thể nhận XML như thế này:

<Address Field="Street" Value="123 Main"/> 
<Address Field="StreetPartTwo" Value="Unit B"/> 
<Address Field="State" Value="CO"/> 
<Address Field="Zip" Value="80020"/> 
<Address Field="SomeOtherCrazyValue" Value="Foo"/> 

tôi cần tạo lược đồ XSD xác thực rằng "Đường phố", "Tiểu bang" và "Zip" phải có mặt. Nhưng tôi không quan tâm liệu "StreetPartTwo" và/hoặc "SomeOtherCrazyValue" có xảy ra không.

Nếu tôi biết rằng chỉ ba tôi quan tâm có thể được bao gồm (và mỗi chỉ sẽ được bao gồm một lần), tôi có thể làm một cái gì đó như thế này:

<xs:element name="Address" type="addressType" maxOccurs="unbounded" minOccurs="3"/> 

<xs:complexType name="addressType"> 
    <xs:attribute name="Field" use="required"> 
    <xs:simpleType> 
     <xs:restriction base="xs:string"> 
     <xs:enumeration value="Street"/> 
     <xs:enumeration value="State"/> 
     <xs:enumeration value="Zip"/> 
     </xs:restriction> 
    </xs:simpleType> 
    </xs:attribute> 
</xs:complexType> 

Nhưng won này' t làm việc với trường hợp của tôi bởi vì tôi cũng có thể nhận được những yếu tố địa chỉ khác (cũng có thuộc tính "Field") mà tôi không quan tâm.

Bất kỳ ý tưởng nào về cách tôi có thể đảm bảo nội dung tôi quan tâm hiện diện nhưng cũng cho phép các nội dung khác?

TIA! Sean

+0

Tôi không nghĩ rằng đề nghị của bạn sẽ làm việc dù sao, ngay cả khi bạn không có khả năng để có SomeOtherCrazyValue thuộc tính. Lý do là, lược đồ được đề xuất của bạn sẽ báo cáo là hợp lệ, một tài liệu XML có các phần tử ''

', mỗi phần tử có thuộc tính Đường phố. (Không có Zip, Không có Tiểu bang). Lược đồ của bạn sẽ không giải quyết được điều đó. – Cheeso

+0

Hmm, điều đó đúng. Trong miền của tôi, các yếu tố khác sẽ ngăn điều này xảy ra. Nhưng trong trường hợp chung nó chắc chắn có thể. Tôi sẽ thêm một ghi chú trong câu hỏi ban đầu về phần đó. Tất nhiên, câu hỏi thực sự của tôi vẫn mở. Cảm ơn Cheeso! – scrotty

Trả lời

6

Bạn không thể thực hiện xác thực mà bạn tìm kiếm, chỉ với Lược đồ XML.

Theo "XML Schema Part 1: Structures" specification ...

Khi hai hoặc nhiều hạt chứa trực tiếp hoặc gián tiếp trong {} hạt của một nhóm người mẫu đã hệt tên tờ khai yếu tố như họ {} hạn, các định nghĩa kiểu các tờ khai đó phải là giống nhau.

Không có nghĩa là bạn không thể xây dựng giản đồ sẽ xác thực tài liệu chính xác. Điều đó nghĩa là gì, bạn không thể xây dựng một lược đồ sẽ không xác thực được trên một số tài liệu không chính xác. Và khi tôi nói "không chính xác", tôi có nghĩa là các tài liệu vi phạm các ràng buộc mà bạn đã nêu bằng tiếng Anh.

Ví dụ, giả sử bạn có một tài liệu bao gồm ba yếu tố Street, như thế này:

<Address Field="Street" Value="123 Main"/> 
<Address Field="Street" Value="456 Main"/> 
<Address Field="Street" Value="789 Main"/> 
<Address Field="SomeOtherCrazyValue" Value="Foo"/> 

Theo giản đồ của bạn, tài liệu đó là một địa chỉ hợp lệ. Có thể thêm ràng buộc xs:unique vào lược đồ của bạn để nó từ chối các tài liệu bị hỏng đó. Nhưng ngay cả với xs: unique, validating với lược đồ như vậy sẽ khai báo rằng một số tài liệu không chính xác khác hợp lệ - ví dụ một tài liệu có ba thành phần <Address>, mỗi phần tử có một thuộc tính Field duy nhất, nhưng không có thuộc tính nào có Field="Zip".

Trên thực tế, không thể tạo ra một lược đồ XML W3C để chính thức hóa các ràng buộc đã nêu của bạn. Phần tử <xs:all>gần như khiến bạn trở nên hấp dẫn, nhưng nó chỉ áp dụng cho các thành phần, không áp dụng cho các thuộc tính. Và, nó không thể được sử dụng với một phần mở rộng, vì vậy bạn không thể nói, trong Lược đồ XML của W3C, "tất cả các phần tử này theo thứ tự bất kỳ, cộng với bất kỳ phần tử nào khác".


Để thực hiện việc xác nhận bạn tìm kiếm, lựa chọn của bạn là:

  1. dựa vào một cái gì đó khác hơn so với XML Schema,
  2. thực hiện xác nhận trong nhiều bước, sử dụng XML Schema cho bước đầu tiên và một thứ khác cho bước thứ hai.

Tùy chọn đầu tiên, tôi nghĩ bạn có thể sử dụng Relax NG để thực hiện điều đó. Nhược điểm của nó là, nó không phải là một tiêu chuẩn và như xa như tôi có thể nói, nó không được hỗ trợ rộng rãi cũng không phát triển. Nó sẽ giống như học Gaelic để thể hiện một ý nghĩ. Không có gì sai với Gaelic, nhưng nó là một loại đường dẫn ngôn ngữ, và I think RelaxNG is, too.

Đối với tùy chọn thứ hai, một cách tiếp cận sẽ được xác nhận đối với giản đồ của bạn như là bước đầu tiên, và sau đó, như là bước thứ hai:

A. áp dụng một XSL chuyển đổi mà sẽ chuyển đổi <Address> yếu tố thành phần tử có tên cho giá trị của thuộc tính Trường của họ. Đầu ra của mà chuyển đổi sẽ trông như thế này:

<root> 
    <Street Value="101 Bellavista Drive"/> 
    <State Value="Confusion"/> 
    <Zip Value="10101"/> 
</root> 

B. xác nhận sản lượng mà chuyển chống lại một sơ đồ khác nhau, mà trông giống như sau:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      elementFormDefault="qualified"> 
    <xs:element name="root"> 
    <xs:complexType> 
     <xs:all> 
     <xs:element maxOccurs="1" minOccurs="1" ref="Street" /> 
     <xs:element maxOccurs="1" minOccurs="1" ref="State" /> 
     <xs:element maxOccurs="1" minOccurs="1" ref="Zip" /> 
     </xs:all> 
    </xs:complexType> 
    </xs:element> 

    <xs:element name="Street"> 
    <xs:complexType> 
     <xs:attribute name="Value" use="required" type="xs:string"/> 
    </xs:complexType> 
    </xs:element> 
    <xs:element name="State"> 
    <xs:complexType> 
     <xs:attribute name="Value" use="required" type="xs:string"/> 
    </xs:complexType> 
    </xs:element> 
    <xs:element name="Zip"> 
    <xs:complexType> 
     <xs:attribute name="Value" use="required" type="xs:string"/> 
    </xs:complexType> 
    </xs:element> 

</xs:schema> 

Bạn sẽ cần phải mở rộng schema mà để xử lý các thành phần khác như <SomeOtherCrazyValue> trong đầu ra của biến đổi. Hoặc bạn có thể cấu trúc biến đổi xsl để không phát ra các phần tử không phải là một trong {State, Street, Zip}.

Chỉ cần rõ ràng, tôi hiểu rằng bạn không thể thay đổi XML mà bạn nhận được. Cách tiếp cận này sẽ không đòi hỏi điều đó. Nó chỉ sử dụng phương pháp xác thực 2 bước hợp lý. Khi bước xác thực thứ 2 hoàn tất, bạn có thể hủy kết quả của phép biến đổi.


EDIT - Trên thực tế, Sean, suy nghĩ về vấn đề này một lần nữa, bạn có thể chỉ cần sử dụng bước B. Giả sử XSL bạn chuyển đổi chỉ Loại bỏ từ tài liệu chỉ <Address> yếu tố mà không có Nhà nước, đường hoặc Zip cho giá trị thuộc tính Field. Nói cách khác, sẽ không có <Address Field="SomeOtherCrazyValue"...>. Kết quả của phép biến đổi đó có thể được xác nhận hợp lệ với lược đồ của bạn, sử dụng một maxOccurs = "3", minOccurs = "3" và xs: unique.

+0

Phản hồi tuyệt vời, Cheeso. Cảm ơn bạn! Những gì bạn viết là những gì tôi nghi ngờ. Tôi sẽ phải suy nghĩ về đề xuất của bạn về việc sử dụng phép biến đổi xsl (hoặc RelaxNG/Gaelic; ^). Suy nghĩ ban đầu của tôi là vì tôi tình cờ unmarshalling xml để Java pojos, tôi có thể viết một thói quen đơn giản mà kiểm tra chúng tại thời điểm đó. Nhưng tất nhiên là nó có thể, làm tất cả trong một xsd duy nhất sẽ có lợi hơn. Cảm ơn bạn lần nữa! Sean – scrotty

+0

không có prob - thực sự tôi nghĩ RelaxNG là tùy chọn "Gaelic". Làm việc chuyển đổi XSL là một thay thế cho việc học Gaelic - chỉ cần thêm công việc bằng một ngôn ngữ mà bạn đã biết. – Cheeso

+0

ps: Tôi biết ai đó sẽ dẫm lên tôi để so sánh RelaxNG với Gaelic. – Cheeso

0

Tôi có cùng một vấn đề như bạn nhưng đã khắc phục bằng một mẹo.

Yêu cầu XML

<request> 
    <url>Abcd</url> 
    <base-url>XXXXX/</base-url> 
    <args src="url"> 
     <arg name="languageCode">NL</arg> 
     <arg name="version">1</arg> 
     <arg name="offerId">10</arg> 
     <arg name="rewardId">1234</arg> 
    </args> 
</request> 

Bây giờ sử dụng một XSLT và chuyển đổi nó,

mã XSLT

<?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="@* | node()"> 
<xsl:copy> 
<xsl:apply-templates select="@* | node()" /> 
</xsl:copy> 
</xsl:template> 
<xsl:template match="arg"> 
<xsl:element name="{@name}"> 
<xsl:apply-templates /> 
</xsl:element> 
</xsl:template> 
</xsl:stylesheet> 

XML trở thành

<?xml version="1.0" encoding="UTF-8"?> 
<request> 

    <url>abcd</url> 
    <base-url>XXXXXXX</base-url> 
    <args src="url"> 
     <languageCode>NL</languageCode> 
     <version>1</version> 
     <offerId>10</offerId> 
     <rewardId>1234</rewardId> 
    </args> 
</request> 

Bây giờ áp dụng XSD

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xs:element name="request"> 
    <xs:complexType> 
     <xs:sequence> 
     <xs:element type="xs:string" name="url"/> 
     <xs:element type="xs:string" name="base-url"/> 
     <xs:element name="args" maxOccurs="unbounded" minOccurs="0"> 
      <xs:complexType mixed="true"> 
      <xs:sequence> 
       <xs:element type="xs:string" name="languageCode" minOccurs="0"/> 
       <xs:element type="xs:string" name="version" minOccurs="0"/> 
       <xs:element type="xs:string" name="offerId" minOccurs="1"/> 
       <xs:element type="xs:string" name="rewardId" minOccurs="1"/> 
      </xs:sequence> 
      <xs:attribute type="xs:string" name="src" use="optional"/> 
      </xs:complexType> 
     </xs:element> 
     </xs:sequence> 
    </xs:complexType> 
    </xs:element> 
</xs:schema> 
Các vấn đề liên quan