JavaRush /Java 博客 /Random-ZH /Java 程序员的 XML 基础知识。第 2 部分(共 3 部分)
Ярослав
第 40 级
Днепр

Java 程序员的 XML 基础知识。第 2 部分(共 3 部分)

已在 Random-ZH 群组中发布

介绍

你好,我的文章的亲爱的读者。这是有关 XML 的系列中的第二篇文章,本文将讨论 XML 命名空间和 XML 架构。
XML 基础知识
就在最近,我自己对此一无所知,但我已经掌握了很多材料,并将尝试用简单的语言解释这两个重要的主题。我想说,模式是一种非常先进的用于验证 XML 文档的机制,并且比 DTD 更实用,因此这里不会对它们进行完整的研究。让我们开始吧 :)

XML命名空间

命名空间的意思是“名称空间”,但在本文中,我经常将俄语表达替换为简单的命名空间,因为它更短且更容易理解。XML命名空间是一项技术,其主要目的是确保XML文件中的所有元素都是唯一的并且不会发生混淆。由于这些是 Java 课程,因此 Java 包中也提供了相同的技术。如果我们可以将两个同名的类放在一起并使用它们,我们如何确定我们需要哪个类?这个问题可以通过包来解决 - 我们可以简单地将类放在不同的包中并从那里导入它们,指定所需包的确切名称及其路径,或者简单地指定所需类的完整路径。 Java 程序员的 XML 基础知识。 第 2 部分(共 3 - 1 部分)现在,我们可以这样做:
public class ExampleInvocation {
    public static void main(String[] args) {
        // Creation экземпляра класса из первого пакета.
        example_package_1.Example example1 = new example_package_1.Example();

        // Creation экземпляра класса из второго пакета.
        example_package_2.Example example2 = new example_package_2.Example();

        // Creation экземпляра класса из третьего пакета.
        example_package_3.Example example3 = new example_package_3.Example();
    }
}
在 XML 命名空间中,一切都几乎相同,只是略有不同。本质是一样的:如果元素是相同的(比如类),那么我们只需在不同的命名空间(指定包)中使用它们,那么即使元素(类)的名称开始重合,我们仍然会从空间(包)访问特定元素。例如:我们在 XML 中有两个元素 - 预测(oracle)和 Oracle 数据库。
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <oracle>
        <connection value="jdbc:oracle:thin:@10.220.140.48:1521:test1" />
        <user value="root" />
        <password value="111" />
    </oracle>

    <oracle>
        Сегодня вы будете заняты весь день.
    </oracle>
</root>
当我们处理这个 XML 文件时,如果我们收到的是预测而不是数据库,我们会感到非常困惑,反之亦然。为了解决元素的碰撞,我们可以为每个元素分配自己的空间来区分它们。为此有一个特殊属性 - xmlns:prefix=“命名空间的唯一值”。然后,我们可以为元素添加前缀,以表明它是该命名空间的一部分(本质上,我们必须创建一个包路径 - 命名空间,然后为每个元素添加它所属的包的前缀)。
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <database:oracle xmlns:database="Unique ID #1">
        <connection value="jdbc:oracle:thin:@10.220.140.48:1521:test1" />
        <user value="root" />
        <password value="111" />
    </database:oracle>

    <oracle:oracle xmlns:oracle="Unique ID #2">
        Сегодня вы будете заняты весь день.
    </oracle:oracle>
</root>
在此示例中,我们声明了两个命名空间:database 和 oracle。现在您可以在元素之前使用命名空间前缀。如果现在不清楚,也不必害怕。其实很简单。起初,我想更快地写出这部分文章,但周三之后我决定需要更多地关注这个主题,因为很容易感到困惑或不理解某些东西。现在我们将重点关注 xmlns 属性。那么,另一个例子:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="https://www.standart-namespace.com/" xmlns:gun="https://www.gun-shop.com/" xmlns:fish="https://www.fish-shop.com/">
    <gun:shop>
        <gun:guns>
            <gun:gun name="Revolver" price="1250$" max_ammo="7" />
            <gun:gun name="M4A1" price="3250$" max_ammo="30" />
            <gun:gun name="9mm Pistol" price="450$" max_ammo="12" />
        </gun:guns>
    </gun:shop>

    <fish:shop>
        <fish:fishes>
            <fish:fish name="Shark" price="1000$" />
            <fish:fish name="Tuna" price="5$" />
            <fish:fish name="Capelin" price="1$" />
        </fish:fishes>
    </fish:shop>
</root>
您可以使用空间枪查看常规 XML,用于枪支商店的独特元素和用于钓鱼商店的鱼的独特元素。您可以看到,通过创建空间,我们同时将一个商店元素用于两个不同的东西 - 武器店和鱼店,并且由于我们声明了空间,我们确切地知道它是哪种商店。最有趣的事情将从方案中开始,此时我们将能够以这种方式验证具有相同元素的不同结构。xmlns 是用于声明命名空间的属性;它可以在任何元素中指定。命名空间声明的示例:
xmlns:shop= «https://barber-shop.com/»
冒号后面是一个前缀 - 这是一个空间引用,然后可以在元素之前使用它来指示它们来自该空间。xmlns 值必须是唯一字符串。理解这一点非常重要:使用网站链接或 URI 来声明命名空间是很常见的。该规则是标准的,因为链接的 URI 或 URL 是唯一的,但这正是它变得非常混乱的地方。请记住:该值可以是您想要的任何字符串,但为了确保它是唯一且标准的,您需要使用 URL 或 URI。事实上,您可以使用任何字符串,如 oracle 中的示例所示:
xmlns:oracle="Unique ID #2"
xmlns:database="Unique ID #1"
声明命名空间时,可以在元素本身及其内的所有元素上使用它,因此在根元素上声明的命名空间可以在所有元素上使用。这可以在最后一个示例中看到,下面是一个更具体的示例:
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <el1:element1 xmlns:el1="Element#1 Unique String">
        <el1:innerElement>

        </el1:innerElement>
    </el1:element1>


    <el2:element2 xmlns:el2="Element#2 Unique String">
        <el2:innerElement>

        </el2:innerElement>
    </el2:element2>


    <el3:element3 xmlns:el3="Element#3 Unique String">
        <el3:innerElement>
            <el1:innerInnerElement> <!-- Так нельзя, потому что пространство el1 объявлено только в первом элементе, потому может использовать только внутри первого element и его внутренних элементов. -->

            </el1:innerInnerElement>
        </el3:innerElement>
    </el3:element3>
</root>
这里有一个重要的细节:根元素中还有一个标准名称空间。如果声明其他命名空间,则会覆盖默认命名空间并且无法使用它。然后,您需要在根元素(之前声明的任何元素)前面放置某种空格前缀。然而,这也可能被欺骗:您可以显式声明标准空间。在 xmlns 之后不要使用前缀,而是立即写下一些值就足够了,所有没有前缀的元素都将属于这个特定的命名空间。最后一个例子使用了这个:
<root xmlns="https://www.standart-namespace.com/" xmlns:gun="https://www.gun-shop.com/" xmlns:fish="https://www.fish-shop.com/">
我们明确声明了标准空间,以避免使用枪或鱼,因为根元素既不是钓鱼店也不是武器的实体,因此使用任何一个空间在逻辑上都是不正确的。接下来:如果您创建了 xmlns:a 和 xmlns:b,但它们具有相同的值,那么这是相同的空间,并且它们不是唯一的。这就是为什么您应该始终使用唯一值,因为违反此规则可能会产生大量错误。例如,如果我们有这样声明的空格:
xmlns="https://www.standart-namespace.com/" xmlns:gun="https://www.gun-shop.com/" xmlns:fish="https://www.gun-shop.com/"
那么我们的钓鱼店就会变成武器店,前缀仍然是鱼店。这些都是空间的要点。我花了相当多的时间把它们全部收集起来并减少它们,然后将它们清晰地表达出来,因为互联网上的空间信息非常庞大,而且往往只是水,所以这里的大部分内容都是我通过尝试自己学会的和错误。如果您仍有疑问,可以尝试使用文章末尾的链接阅读材料。

XML模式

我想说,这篇文章只是冰山一角,因为主题非常广泛。如果您想更详细地熟悉方案并学习如何自己编写任何复杂的方案,那么在文章末尾将有一个链接,其中所有内容都将涉及不同的类型、限制、扩展等。我想从理论开始。方案具有 .xsd(xml 方案定义)格式,是 DTD 的更高级和流行的替代方案:它们还可以创建元素、描述元素等等。然而,添加了很多好处:类型检查、命名空间支持和更广泛的功能。还记得当我们谈论 DTD 时,有一个缺点是它不支持空格吗?现在我们已经研究了这一点,我将解释一下:如果可以从 DTD 导入两个或多个具有相同元素的模式,我们就会发生冲突(巧合)并且根本无法使用它们,因为目前还不清楚我们需要哪个元素。XSD 解决了这一问题,因为您可以将模式导入到一个特定空间并使用它。本质上,每个 XSD 模式都有一个目标空间,这意味着模式应该写入 XML 文件中的哪个空间。因此,在 XML 文件本身中,我们只需要创建模式中预定义的这些空间并为其分配前缀,然后将必要的模式连接到每个模式,之后我们可以安全地使用模式中的元素,替换来自我们导入原理图的空间。所以,我们有一个例子:
<?xml version="1.0" encoding="UTF-8"?>
<house>
    <address>ул. Есенина, дом №5</address>
    <owner name="Ivan">
        <telephone>+38-094-521-77-35</telephone>
    </owner>
</house>
我们想用模式来验证它。首先,我们需要一个模式:
<?xml version="1.0"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="https://www.nedvigimost.com/">
    <element name="house">
        <complexType>
            <sequence>
                <element name="address" type="string" maxOccurs="unbounded" minOccurs="0" />
                <element name="owner" maxOccurs="unbounded" minOccurs="0" >
                    <complexType>
                        <sequence>
                            <element name="telephone" type="string" />
                        </sequence>
                        <attribute name="name" type="string" use="required"/>
                    </complexType>
                </element>
            </sequence>
        </complexType>
    </element>
</schema>
正如您所看到的,架构也是 XML 文件。您可以直接在 XML 中编写您需要的内容。该模式能够验证上面示例中的 XML 文件。例如:如果所有者没有名字,电路就会看到这一点。此外,由于序列元素,地址应始终排在第一位,然后是房子的所有者。有普通元素和复杂元素。常规元素是仅存储某种类型数据的元素。例子:
<element name="telephone" type="string" />
这就是我们声明存储字符串的元素的方式。该元素内不应有其他元素。还有复杂的元素。复杂元素能够在其内部存储其他元素和属性。然后,您不需要指定类型,只需开始在元素内编写复杂类型即可。
<complexType>
    <sequence>
        <element name="address" type="string" maxOccurs="unbounded" minOccurs="0" />
        <element name="owner" maxOccurs="unbounded" minOccurs="0" >
            <complexType>
                <sequence>
                    <element name="telephone" type="string" />
                </sequence>
                <attribute name="name" type="string" use="required"/>
            </complexType>
        </element>
    </sequence>
</complexType>
也可以采用不同的方式:您可以单独创建一个复杂类型,然后将其替换为 type。仅在编写此示例时,由于某种原因需要在某种前缀下声明空格,而不是使用标准前缀。总的来说,结果是这样的:
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="https://www.nedvigimost.com/">
    <xs:element name="house" type="content" />

    <xs:complexType name="content">
        <xs:sequence>
            <xs:element name="address" type="xs:string" maxOccurs="unbounded" minOccurs="0" />
            <xs:element name="owner" maxOccurs="unbounded" minOccurs="0" >
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="telephone" type="xs:string" />
                    </xs:sequence>
                    <xs:attribute name="name" type="xs:string" use="required"/>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:schema>
这样,我们可以单独创建自己的类型,然后在 type 属性中的某个位置替换它们。这非常方便,因为它允许您在不同的地方使用一种类型。我想详细谈谈连接电路,到这里就结束了。连接电路有两种方法:进入特定空间并直接连接。

第一种电路连接方式

第一种方法假设电路具有特定的目标空间。它是使用方案元素上的 targetNamespace 属性指定的。然后在 XML 文件中创建相同的空间就足够了,然后在那里“加载”模式:
<?xml version="1.0" encoding="UTF-8"?>
<nedvig:house xmlns:nedvig="https://www.nedvigimost.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.nedvigimost.com/ example_schema1.xsd">
    <address>ул. Есенина, дом №5</address>
    <owner name="Ivan">
        <telephone>+38-094-521-77-35</telephone>
    </owner>
</nedvig:house>
理解两行很重要:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemeLocation="https://www.nedvigimost.com/ example_schema1.xsd"
第一行——记住它。将其视为一个有助于将原理图加载到需要的位置的对象。 第二行是具体的下载。schemaLocation 接受“值 - 值”形式的值列表,以空格分隔。第一个参数是命名空间,它必须与架构中的目标命名空间(targetNamespace 值)匹配。第二个参数是模式的相对或绝对路径。由于这是一个 LIST 值,因此您可以在示例中的方案后面放置一个空格,然后再次输入目标空间和另一个方案的名称,依此类推。 重要的:为了让架构稍后验证某些内容,您需要声明此空间并使用前缀。仔细看最后一个例子:
<?xml version="1.0" encoding="UTF-8"?>
<nedvig:house xmlns:nedvig="https://www.nedvigimost.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.nedvigimost.com/ example_schema1.xsd">
    <address>ул. Есенина, дом №5</address>
    <owner name="Ivan">
        <telephone>+38-094-521-77-35</telephone>
    </owner>
</nedvig:house>
我们在 nedvig 前缀上创建了这个目标空间,然后使用它。因此,我们的元素开始得到验证,因为我们开始使用引用目标模式空间的空间。

第二种电路连接方式

连接电路的第二种方式意味着电路没有特定的目标空间。然后您只需将其连接到 XML 文件,它就会对其进行验证。这几乎以相同的方式完成,只是您不能在 XML 文件中声明空格,而只需连接模式即可。
<?xml version="1.0" encoding="UTF-8"?>
<house xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="example_schema1.xsd">
    <address>ул. Есенина, дом №5</address>
    <owner name="Ivan">
        <telephone>+38-094-521-77-35</telephone>
    </owner>
</house>
正如您所看到的,这是使用 noNamespaceSchemaLocation 并指定架构路径来完成的。即使模式没有目标空间,文档也会被验证。最后一步:我们可以将其他图表导入到图表中,然后在另一个图表中使用一个图表中的元素。因此,我们可以在某些电路中使用其他电路中已有的元件。例子:

声明所有者类型的架构:

<?xml version="1.0" encoding="UTF-8" ?>
<schema targetNamespace="bonus" xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
        <complexType name="owner">
            <all>
                <element name="telephone" type="string" />
            </all>
            <attribute name="name" type="string" />
        </complexType>
</schema>

第二个架构,使用第一个架构中的所有者类型:

<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="main" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:bonus="bonus" elementFormDefault="qualified">
    <import namespace="bonus" schemaLocation="xsd2.xsd" />
    <element name="house">
        <complexType>
            <all>
              <element name="address" type="string" />
                <element name="owner" type="bonus:owner" />
            </all>
        </complexType>
    </element>
</schema>
第二种方案使用以下结构:
<import namespace="bonus" schemaLocation="xsd2.xsd" />
使用它,我们将类型和元素从一种模式导入到另一种模式中,并进入奖励空间。因此,我们可以访问 Bonus:owner 类型。在下一行中我们使用了它:
<element name="owner" type="bonus:owner" />
还要注意以下行:
elementFormDefault="qualified"
此属性在模式中声明,意味着在 XML 文件中,每个元素必须在其前面声明显式前缀。如果不存在,那么我们只需要声明一个带有前缀的外部元素,并且我们还需要在内部的所有元素中设置前缀,明确表明我们正在使用该方案的元素。事实上,这里是一个由导入另一个模式的模式验证的 XML 文件的示例:
<?xml version="1.0" encoding="UTF-8"?>
<nedvig:house xmlns:nedvig="main" xmlns:bonus="bonus" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="main xsd.xsd">
    <nedvig:address>ул. Есенина, дом №5</nedvig:address>
    <nedvig:owner name="Ivan">
        <bonus:telephone>+38-094-521-77-35</bonus:telephone>
    </nedvig:owner>
</nedvig:house>
在行中:
<bonus:telephone>+38-094-521-77-35</bonus:telephone>
我们需要显式声明额外的命名空间,它指向第一个模式的目标空间,因为 elementFormDefault 是合格的(检查),所以所有元素都必须显式指示它们的空间。

文章结束

下一篇文章将是该系列的最后一篇文章,并且将介绍如何使用 Java 处理 XML 文件。我们将学习以不同的方式获取信息等等。我希望本文有用,即使在某些地方存在错误,它也会教您一些有用的新知识,或者可能只是让您有机会更好地理解 XML 文件。 对于那些想更详细地探索这一点的人,我决定整理一组链接:
  • XSD 简单元素- 从本文开始阅读并继续,有关该方案的所有信息都收集在那里,并且或多或少有清晰的解释,仅用英语。您可以使用翻译器。

  • 关于命名空间的视频,如果第一个观点不清楚,那么聆听关于某事的另一个观点总是有用的。

  • 命名空间 XML是使用命名空间的一个很好的示例,并且非常全面。

  • XML 基础知识 - 命名空间- 另一篇关于命名空间的短文。

  • 《使用 XML 模式定义元素的基础知识》也是一本非常有用的模式参考,但您需要慢慢地、仔细地阅读它,深入研究其中的内容。

这是肯定的,我希望如果您想从中学到更深入的东西,这些链接会对您有所帮助。我自己浏览了所有这些来源,研究了所有材料,总的来说,这些是我看过的所有来源中最有用的,因为它们中的每一个要么提高了对我在其他地方已经读过的内容的理解,要么让我学到了一些新东西,但很多东西只是在练习过程中完成的。因此,对于那些真正想很好地理解这一切的人,我的建议是:研究命名空间,然后如何轻松地将模式连接到 XML 文件,然后如何在模式中编写文档结构。最重要的是,练习。感谢大家的关注,祝您编程好运 :) 上一篇文章:[竞赛] Java 程序员的 XML 基础知识 - 第 1 部分(共 3 部分) 下一篇文章:[竞赛] Java 程序员的 XML 基础知识 - 第 3.1 部分(共 3 部分)- SAX
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION