首页 > 解决方案 > 使用 XSLT 将 XML 文件拆分为多个文件

问题描述

我无法使用 XSLT 将 XML 文件拆分为多个文件。

我尝试根据附加的 XSLT 代码拆分文件。我已成功拆分文件。但是,我无法弄清楚如何复制文件并为原始文件中的每个文件创建一个。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0">

<xsl:output method="xml" indent="yes" name="xml"/>


<xsl:template match="/">
<xsl:for-each select="//FlightGroup">
<xsl:variable 
    name="filehandle"
    select="//Info/Campaign/CampaignNumber"/>
<xsl:variable
    name="FlightGroupId"
    select="FlightGroup-id"
    />
<xsl:variable name="filename"
  select="concat('file:///c:/Temp/',$filehandle,'_',$FlightGroupId,'.xml')" />
<xsl:value-of select="$filename" />   <!-- Creating  -->
<xsl:result-document href="{$filename}" format="xml">
    <Data>
        <filename><xsl:value-of select = "concat($filehandle, '_', $FlightGroupId)"/></filename>
        <xsl:copy-of select = "//OrderCustomers" />
        <xsl:copy-of select = "//Campaign"/>
        <xsl:copy-of select = "." />
    </Data>
    </xsl:result-document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

我需要能够为每个飞行组生成一个文件,其余文件是原始文件的副本。

例如:

源文件:

<?xml version="1.0" encoding="utf-8"?>
<Data>
  <Info>
    <OrderCustomers>
      <OrderCustomer>
        <IsPrimaryOrderer>true</IsPrimaryOrderer>
        <IsPrimaryPayor>true</IsPrimaryPayor>
        <Customer>
          <account-number>20007658</account-number>
          <accountid>7659</accountid>
          <Name1>DIGITAL TEST ACCOUNT</Name1>
          <Phone>0000000000</Phone>
          <Type-id>2</Type-id>
          <Type>Commercial</Type>
          <Company-id>1</Company-id>
          <Company>Company1</Company>
          <Address>
            <Addr1>123 Main</Addr1>
            <City>Anytown</City>
            <Postal-Code>99999</Postal-Code>
            <Country-id>1</Country-id>
            <Country>USA</Country>
            <State-id>113</State-id>
            <State>TX</State>
          </Address>
          <PrimarySalesRep>Rep1</PrimarySalesRep>
          <Category>Local</Category>
          <PaymentMethod-id>4</PaymentMethod-id>
          <PaymentMethod>Credit Card</PaymentMethod>
        </Customer>
      </OrderCustomer>
    </OrderCustomers>
    <ad-ordered-by>test</ad-ordered-by>
    <publication-code>Y</publication-code>
    <pagination-code>N</pagination-code>
    <ProductionCode>N</ProductionCode>
    <ad-sold-by-id>113</ad-sold-by-id>
    <ad-sold-by>Rep1</ad-sold-by>
    <ad-sold-by-name>National</ad-sold-by-name>
    <ad-order-taker-id>15</ad-order-taker-id>
    <ad-order-taker>jsmith</ad-order-taker>
    <CreateDate>07022019 13:50:31</CreateDate>
    <LastEditDate>07022019 13:50:33</LastEditDate>
    <LastEditUser>jsmith</LastEditUser>
    <order-number>00000994</order-number>
    <price>10.00</price>
    <company-id>1</company-id>
    <company>Company1</company>
    <CreationDate>070220191350</CreationDate>
    <Campaign>
      <CampaignId>205</CampaignId>
      <CampaignNumber>00994-01</CampaignNumber>
      <Name>DIGITAL TEST ACCOUNT01</Name>
      <Type-id>1</Type-id>
      <Type>Banner</Type>
      <Category-id>1</Category-id>
      <Category>Standard</Category>
      <StartDate>07072019</StartDate>
      <EndDate>07312019</EndDate>
      <Quantity>1000</Quantity>
      <Price>10.00</Price>
      <CampaignUnit>
        <Id>7</Id>
        <Name>300x250</Name>
        <Width>300</Width>
        <Height>250</Height>
      </CampaignUnit>
      <CampaignUnit>
        <Id>6</Id>
        <Name>728x90</Name>
        <Width>728</Width>
        <Height>90</Height>
      </CampaignUnit>
      <FlightGroup>
        <Name>Group1</Name>
        <FlightGroup-id>296</FlightGroup-id>
        <CampaignUnit-id>7</CampaignUnit-id>
        <CampaignUnit>300x250</CampaignUnit>
        <Quantity>500</Quantity>
        <StartDate>07072019</StartDate>
        <EndDate>07312019</EndDate>
        <Flight>
          <Flight-id>666</Flight-id>
          <Site-id>2</Site-id>
          <NetworkId>3</NetworkId>
          <Network>Digital</Network>
          <Site>anysite.com</Site>
          <Section-id>20</Section-id>
          <Section>Business</Section>
          <Page-id>3</Page-id>
          <Page>ATF</Page>
          <SiteURL>www.anysite.com</SiteURL>
          <InvoicedAlreadyFlag>0</InvoicedAlreadyFlag>
          <PublishedFlag>true</PublishedFlag>
          <Price>2.50</Price>
          <Quantity>250</Quantity>
          <dates>
            <date Insertion-id="26901" PublishedFlag="true">07072019</date>
            <date Insertion-id="26902" PublishedFlag="true">07082019</date>
            <date Insertion-id="26903" PublishedFlag="true">07092019</date>
            <date Insertion-id="26904" PublishedFlag="true">07102019</date>
            <date Insertion-id="26905" PublishedFlag="true">07112019</date>
          </dates>
        </Flight>
        <Flight>
          <Flight-id>667</Flight-id>
          <Site-id>2</Site-id>
          <NetworkId>3</NetworkId>
          <Network>Digital</Network>
          <Site>anysite.com</Site>
          <Section-id>20</Section-id>
          <Section>Business</Section>
          <Page-id>4</Page-id>
          <Page>BTF</Page>
          <SiteURL>www.anysite.com</SiteURL>
          <Quantity>250</Quantity>
          <dates>
            <date Insertion-id="26926" PublishedFlag="true">07072019</date>
            <date Insertion-id="26927" PublishedFlag="true">07082019</date>
            <date Insertion-id="26928" PublishedFlag="true">07092019</date>
            <date Insertion-id="26929" PublishedFlag="true">07102019</date>
            <date Insertion-id="26930" PublishedFlag="true">07112019</date>
          </dates>
        </Flight>
      </FlightGroup>
      <FlightGroup>
        <Name>Group2</Name>
        <FlightGroup-id>297</FlightGroup-id>
        <CampaignUnit-id>6</CampaignUnit-id>
        <CampaignUnit>728x90</CampaignUnit>
        <Quantity>500</Quantity>
        <StartDate>07072019</StartDate>
        <EndDate>07312019</EndDate>
        <Flight>
          <Flight-id>668</Flight-id>
          <Site-id>2</Site-id>
          <NetworkId>3</NetworkId>
          <Network>Digital</Network>
          <Site>anysite.com</Site>
          <Section-id>20</Section-id>
          <Section>Business</Section>
          <Page-id>3</Page-id>
          <Page>ATF</Page>
          <SiteURL>www.anysite.com</SiteURL>
          <Quantity>250</Quantity>
          <dates>
            <date Insertion-id="26951" PublishedFlag="true">07072019</date>
            <date Insertion-id="26952" PublishedFlag="true">07082019</date>
            <date Insertion-id="26953" PublishedFlag="true">07092019</date>
            <date Insertion-id="26954" PublishedFlag="true">07102019</date>
            <date Insertion-id="26955" PublishedFlag="true">07112019</date>
          </dates>
        </Flight>
        <Flight>
          <Flight-id>669</Flight-id>
          <Site-id>2</Site-id>
          <NetworkId>3</NetworkId>
          <Network>Digital</Network>
          <Site>anysite.com</Site>
          <Section-id>20</Section-id>
          <Section>Business</Section>
          <Page-id>4</Page-id>
          <Page>BTF</Page>
          <SiteURL>www.anysite.com</SiteURL>
          <Quantity>250</Quantity>
          <dates>
            <date Insertion-id="26976" PublishedFlag="true">07072019</date>
            <date Insertion-id="26977" PublishedFlag="true">07082019</date>
            <date Insertion-id="26978" PublishedFlag="true">07092019</date>
            <date Insertion-id="26979" PublishedFlag="true">07102019</date>
            <date Insertion-id="26980" PublishedFlag="true">07112019</date>
          </dates>
        </Flight>
      </FlightGroup>
      <FrequencyCap />
      <AdServingId>3</AdServingId>
      <AdServing>DFP</AdServing>
      <CampaignViewTypeId>2</CampaignViewTypeId>
      <CampaignViewType>Impressions</CampaignViewType>
      <CreateDate>07022019 13:50:31</CreateDate>
      <CreateUser>Rep1</CreateUser>
      <LastEditDate>07022019 13:50:33</LastEditDate>
      <LastEditUser>Rep1</LastEditUser>
    </Campaign>
    <Company>
      <ID>1</ID>
      <COMPANYCODE>Company1</COMPANYCODE>
    </Company>
  </Info>
</Data>

文件 #1 - 00994-01_296.xml

<?xml version="1.0" encoding="utf-8"?>
<Data>
  <Info>
    <OrderCustomers>
      <OrderCustomer>
        <IsPrimaryOrderer>true</IsPrimaryOrderer>
        <IsPrimaryPayor>true</IsPrimaryPayor>
        <Customer>
          <account-number>20007658</account-number>
          <accountid>7659</accountid>
          <Name1>DIGITAL TEST ACCOUNT</Name1>
          <Phone>0000000000</Phone>
          <Type-id>2</Type-id>
          <Type>Commercial</Type>
          <Company-id>1</Company-id>
          <Company>Company1</Company>
          <Address>
            <Addr1>123 Main</Addr1>
            <City>Anytown</City>
            <Postal-Code>99999</Postal-Code>
            <Country-id>1</Country-id>
            <Country>USA</Country>
            <State-id>113</State-id>
            <State>TX</State>
          </Address>
          <PrimarySalesRep>Rep1</PrimarySalesRep>
          <Category>Local</Category>
          <PaymentMethod-id>4</PaymentMethod-id>
          <PaymentMethod>Credit Card</PaymentMethod>
        </Customer>
      </OrderCustomer>
    </OrderCustomers>
    <ad-ordered-by>test</ad-ordered-by>
    <publication-code>Y</publication-code>
    <pagination-code>N</pagination-code>
    <ProductionCode>N</ProductionCode>
    <ad-sold-by-id>113</ad-sold-by-id>
    <ad-sold-by>Rep1</ad-sold-by>
    <ad-sold-by-name>National</ad-sold-by-name>
    <ad-order-taker-id>15</ad-order-taker-id>
    <ad-order-taker>jsmith</ad-order-taker>
    <CreateDate>07022019 13:50:31</CreateDate>
    <LastEditDate>07022019 13:50:33</LastEditDate>
    <LastEditUser>jsmith</LastEditUser>
    <order-number>00000994</order-number>
    <price>10.00</price>
    <company-id>1</company-id>
    <company>Company1</company>
    <CreationDate>070220191350</CreationDate>
    <Campaign>
      <CampaignId>205</CampaignId>
      <CampaignNumber>00994-01</CampaignNumber>
      <Name>DIGITAL TEST ACCOUNT01</Name>
      <Type-id>1</Type-id>
      <Type>Banner</Type>
      <Category-id>1</Category-id>
      <Category>Standard</Category>
      <StartDate>07072019</StartDate>
      <EndDate>07312019</EndDate>
      <Quantity>1000</Quantity>
      <Price>10.00</Price>
      <CampaignUnit>
        <Id>7</Id>
        <Name>300x250</Name>
        <Width>300</Width>
        <Height>250</Height>
      </CampaignUnit>
      <CampaignUnit>
        <Id>6</Id>
        <Name>728x90</Name>
        <Width>728</Width>
        <Height>90</Height>
      </CampaignUnit>
      <FlightGroup>
        <Name>Group1</Name>
        <FlightGroup-id>296</FlightGroup-id>
        <CampaignUnit-id>7</CampaignUnit-id>
        <CampaignUnit>300x250</CampaignUnit>
        <Quantity>500</Quantity>
        <StartDate>07072019</StartDate>
        <EndDate>07312019</EndDate>
        <Flight>
          <Flight-id>666</Flight-id>
          <Site-id>2</Site-id>
          <NetworkId>3</NetworkId>
          <Network>Digital</Network>
          <Site>anysite.com</Site>
          <Section-id>20</Section-id>
          <Section>Business</Section>
          <Page-id>3</Page-id>
          <Page>ATF</Page>
          <SiteURL>www.anysite.com</SiteURL>
          <InvoicedAlreadyFlag>0</InvoicedAlreadyFlag>
          <PublishedFlag>true</PublishedFlag>
          <Price>2.50</Price>
          <Quantity>250</Quantity>
          <dates>
            <date Insertion-id="26901" PublishedFlag="true">07072019</date>
            <date Insertion-id="26902" PublishedFlag="true">07082019</date>
            <date Insertion-id="26903" PublishedFlag="true">07092019</date>
            <date Insertion-id="26904" PublishedFlag="true">07102019</date>
            <date Insertion-id="26905" PublishedFlag="true">07112019</date>
          </dates>
        </Flight>
        <Flight>
          <Flight-id>667</Flight-id>
          <Site-id>2</Site-id>
          <NetworkId>3</NetworkId>
          <Network>Digital</Network>
          <Site>anysite.com</Site>
          <Section-id>20</Section-id>
          <Section>Business</Section>
          <Page-id>4</Page-id>
          <Page>BTF</Page>
          <SiteURL>www.anysite.com</SiteURL>
          <Quantity>250</Quantity>
          <dates>
            <date Insertion-id="26926" PublishedFlag="true">07072019</date>
            <date Insertion-id="26927" PublishedFlag="true">07082019</date>
            <date Insertion-id="26928" PublishedFlag="true">07092019</date>
            <date Insertion-id="26929" PublishedFlag="true">07102019</date>
            <date Insertion-id="26930" PublishedFlag="true">07112019</date>
          </dates>
        </Flight>
      </FlightGroup>
      <FrequencyCap />
      <AdServingId>3</AdServingId>
      <AdServing>DFP</AdServing>
      <CampaignViewTypeId>2</CampaignViewTypeId>
      <CampaignViewType>Impressions</CampaignViewType>
      <CreateDate>07022019 13:50:31</CreateDate>
      <CreateUser>Rep1</CreateUser>
      <LastEditDate>07022019 13:50:33</LastEditDate>
      <LastEditUser>Rep1</LastEditUser>
    </Campaign>
    <Company>
      <ID>1</ID>
      <COMPANYCODE>Company1</COMPANYCODE>
    </Company>
  </Info>
</Data>

文件 #2 - 00994-01_297.xml

<?xml version="1.0" encoding="utf-8"?>
<Data>
  <Info>
    <OrderCustomers>
      <OrderCustomer>
        <IsPrimaryOrderer>true</IsPrimaryOrderer>
        <IsPrimaryPayor>true</IsPrimaryPayor>
        <Customer>
          <account-number>20007658</account-number>
          <accountid>7659</accountid>
          <Name1>DIGITAL TEST ACCOUNT</Name1>
          <Phone>0000000000</Phone>
          <Type-id>2</Type-id>
          <Type>Commercial</Type>
          <Company-id>1</Company-id>
          <Company>Company1</Company>
          <Address>
            <Addr1>123 Main</Addr1>
            <City>Anytown</City>
            <Postal-Code>99999</Postal-Code>
            <Country-id>1</Country-id>
            <Country>USA</Country>
            <State-id>113</State-id>
            <State>TX</State>
          </Address>
          <PrimarySalesRep>Rep1</PrimarySalesRep>
          <Category>Local</Category>
          <PaymentMethod-id>4</PaymentMethod-id>
          <PaymentMethod>Credit Card</PaymentMethod>
        </Customer>
      </OrderCustomer>
    </OrderCustomers>
    <ad-ordered-by>test</ad-ordered-by>
    <publication-code>Y</publication-code>
    <pagination-code>N</pagination-code>
    <ProductionCode>N</ProductionCode>
    <ad-sold-by-id>113</ad-sold-by-id>
    <ad-sold-by>Rep1</ad-sold-by>
    <ad-sold-by-name>National</ad-sold-by-name>
    <ad-order-taker-id>15</ad-order-taker-id>
    <ad-order-taker>jsmith</ad-order-taker>
    <CreateDate>07022019 13:50:31</CreateDate>
    <LastEditDate>07022019 13:50:33</LastEditDate>
    <LastEditUser>jsmith</LastEditUser>
    <order-number>00000994</order-number>
    <price>10.00</price>
    <company-id>1</company-id>
    <company>Company1</company>
    <CreationDate>070220191350</CreationDate>
    <Campaign>
      <CampaignId>205</CampaignId>
      <CampaignNumber>00994-01</CampaignNumber>
      <Name>DIGITAL TEST ACCOUNT01</Name>
      <Type-id>1</Type-id>
      <Type>Banner</Type>
      <Category-id>1</Category-id>
      <Category>Standard</Category>
      <StartDate>07072019</StartDate>
      <EndDate>07312019</EndDate>
      <Quantity>1000</Quantity>
      <Price>10.00</Price>
      <CampaignUnit>
        <Id>7</Id>
        <Name>300x250</Name>
        <Width>300</Width>
        <Height>250</Height>
      </CampaignUnit>
      <CampaignUnit>
        <Id>6</Id>
        <Name>728x90</Name>
        <Width>728</Width>
        <Height>90</Height>
      </CampaignUnit>
      <FlightGroup>
        <Name>Group2</Name>
        <FlightGroup-id>297</FlightGroup-id>
        <CampaignUnit-id>6</CampaignUnit-id>
        <CampaignUnit>728x90</CampaignUnit>
        <Quantity>500</Quantity>
        <StartDate>07072019</StartDate>
        <EndDate>07312019</EndDate>
        <Flight>
          <Flight-id>668</Flight-id>
          <Site-id>2</Site-id>
          <NetworkId>3</NetworkId>
          <Network>Digital</Network>
          <Site>anysite.com</Site>
          <Section-id>20</Section-id>
          <Section>Business</Section>
          <Page-id>3</Page-id>
          <Page>ATF</Page>
          <SiteURL>www.anysite.com</SiteURL>
          <Quantity>250</Quantity>
          <dates>
            <date Insertion-id="26951" PublishedFlag="true">07072019</date>
            <date Insertion-id="26952" PublishedFlag="true">07082019</date>
            <date Insertion-id="26953" PublishedFlag="true">07092019</date>
            <date Insertion-id="26954" PublishedFlag="true">07102019</date>
            <date Insertion-id="26955" PublishedFlag="true">07112019</date>
          </dates>
        </Flight>
        <Flight>
          <Flight-id>669</Flight-id>
          <Site-id>2</Site-id>
          <NetworkId>3</NetworkId>
          <Network>Digital</Network>
          <Site>anysite.com</Site>
          <Section-id>20</Section-id>
          <Section>Business</Section>
          <Page-id>4</Page-id>
          <Page>BTF</Page>
          <SiteURL>www.anysite.com</SiteURL>
          <Quantity>250</Quantity>
          <dates>
            <date Insertion-id="26976" PublishedFlag="true">07072019</date>
            <date Insertion-id="26977" PublishedFlag="true">07082019</date>
            <date Insertion-id="26978" PublishedFlag="true">07092019</date>
            <date Insertion-id="26979" PublishedFlag="true">07102019</date>
            <date Insertion-id="26980" PublishedFlag="true">07112019</date>
          </dates>
        </Flight>
      </FlightGroup>
      <FrequencyCap />
      <AdServingId>3</AdServingId>
      <AdServing>DFP</AdServing>
      <CampaignViewTypeId>2</CampaignViewTypeId>
      <CampaignViewType>Impressions</CampaignViewType>
      <CreateDate>07022019 13:50:31</CreateDate>
      <CreateUser>Rep1</CreateUser>
      <LastEditDate>07022019 13:50:33</LastEditDate>
      <LastEditUser>Rep1</LastEditUser>
    </Campaign>
    <Company>
      <ID>1</ID>
      <COMPANYCODE>Company1</COMPANYCODE>
    </Company>
  </Info>
</Data>

标签: xmlxsltxslt-1.0xslt-2.0

解决方案


“我需要能够为每个飞行组生成一个文件,其余文件是原始文件的副本。”:然后使用类似的方法

<xsl:template match="FlightGroup">
  <xsl:result-document href="{/Info/Campaign/CampaignNumber}-{FlightGroup-id}.xml">
      <xsl:apply-templates select="/" mode="split">
         <xsl:with-param name="this-flight-group" select="." tunnel="yes"/>
      </xsl:apply-templates>
  </xsl:result-document>
</xsl:template>

<xsl:template match="@* | node()" mode="split">
  <xsl:copy>
    <xsl:apply-templates select="@* | node()" mode="#current"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="FlightGroup" mode="split">
  <xsl:param name="this-flight-group" tunnel="yes"/>
  <xsl:if test=". is $this-flight-group">
    <xsl:next-match/>
  </xsl:if>
</xsl:template>

应该做。它为未命名默认模式中的元素设置模板FlightGroup并创建结果文档,然后通过命名模式推送整个文档split,将当前FlightGroup元素存储在隧道参数中。该模式设置为使用身份转换作为基础处理,并且在匹配FlightGroup元素时,它有一个模板将隧道参数与FlightGroup基于节点身份的当前处理与is运营商进行比较,在身份的情况下,它只是将处理委托xsl:next-match给身份转换,否则它不会FlightGroup在该模式下进一步处理任何内容。

使用 XSLT 3(由 Saxon 9.8 及更高版本(所有版本)和 Altova XML 2017 R3 及更高版本支持)以及阴影属性和静态参数的新特性,我们甚至可以尝试编写一个采用“拆分”模式的通用解决方案和将“文件名”表达式作为静态参数,有了这个想法,上面的内容将被实现为

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all">

    <xsl:param name="split-pattern" as="xs:string" static="yes" select="'FlightGroup'"/>

    <xsl:param name="file-name-expression" as="xs:string" static="yes" select="'{//Info/Campaign/CampaignNumber}-{FlightGroup-id}.xml'"/>

    <xsl:template _match="{$split-pattern}">
        <xsl:result-document _href="{$file-name-expression}">
            <xsl:apply-templates select="/" mode="split">
                <xsl:with-param name="this-split-element" select="." tunnel="yes"/>
            </xsl:apply-templates>
        </xsl:result-document>
    </xsl:template>

    <xsl:mode name="split" on-no-match="shallow-copy"/>

    <xsl:template _match="{$split-pattern}" mode="split">
        <xsl:param name="this-split-element" tunnel="yes"/>
        <xsl:if test=". is $this-split-element">
            <xsl:next-match/>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

并且任何想要foo使用某个文件名表达式(例如静态字符串split加上子选择id)在某个元素(例如)上拆分的任何人都可以简单地调整静态参数,例如在下面内联完成

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all">

    <xsl:param name="split-pattern" as="xs:string" static="yes" select="'foo'"/>

    <xsl:param name="file-name-expression" as="xs:string" static="yes" select="'split-{id}.xml'"/>

    <xsl:template _match="{$split-pattern}">
        <xsl:result-document _href="{$file-name-expression}">
            <xsl:apply-templates select="/" mode="split">
                <xsl:with-param name="this-split-element" select="." tunnel="yes"/>
            </xsl:apply-templates>
        </xsl:result-document>
    </xsl:template>

    <xsl:mode name="split" on-no-match="shallow-copy"/>

    <xsl:template _match="{$split-pattern}" mode="split">
        <xsl:param name="this-split-element" tunnel="yes"/>
        <xsl:if test=". is $this-split-element">
            <xsl:next-match/>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

但当然 XSLT 3 处理器或 IDE 允许您设置静态参数,甚至无需触摸/更改 XSLT 代码本身。


推荐阅读