顯示具有 XML 標籤的文章。 顯示所有文章
顯示具有 XML 標籤的文章。 顯示所有文章
2015-02-26 14:40

[PHP][Java][C#] 用 XSD 驗證 XML

menu_config.xml 要驗證的 XML
<?xml version="1.0" encoding="utf-8"?>
<menu_config>
    <menu title="文章管理" url="~/Article" target="" allow="">
        <submenu title="列表" url="~/Article/list" target="" allow=""/>
        <submenu/>
        <submenu title="新增" url="~/Article/add" target="" allow=""/>
    </menu>
    <menu/>
    <menu title="帳號管理" url="~/Admin"/>
</menu_config>


menu_config.xsd 結構定義
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">

    <xs:element name="menu_config">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="menu" type="menuType" minOccurs="0" maxOccurs="unbounded" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="menuType">
        <xs:sequence>
            <xs:element name="submenu" type="menuType" minOccurs="0" maxOccurs="unbounded" />
        </xs:sequence>
        <xs:attribute name="title" type="xs:string"/>
        <xs:attribute name="url" type="xs:string"/>
        <xs:attribute name="target" type="xs:string"/>
        <xs:attribute name="allow" type="xs:string"/>
    </xs:complexType>

</xs:schema>
element minOccurs
最少的出現次數,不設置為至少出現 1 次,設置 0 為可有可無。
element maxOccurs
最大的出現次數,設置 unbounded 為無上限。
attribute type
型別必須為 QName,常用的有 xs:string, xs:date, xs:int, xs:integer, xs:decimal, xs:boolean, xs:double, xs:float。


PHP
$xmlFile = 'menu_config.xml';
$xsdFile = 'menu_config.xsd';

/* 啟用自行錯誤處裡 */
libxml_use_internal_errors(true);

$xml = new DOMDocument();
$xml->load($xmlFile);

if (!$xml->schemaValidate($xsdFile)) {
    /* 顯示錯誤訊息 */
    print_r(libxml_get_errors());
    libxml_clear_errors();
}


C#
var menuConfig = XDocument.Load("menu_config.xml");
schemas.Add("", XmlReader.Create("menu_config.xsd"));

menuConfig.Validate(schemas, (o, e) => {
    e.Message.Dump();
});


Java
import java.io.File;
import java.io.IOException;

import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.xml.sax.SAXException;


public class TestXsd {

    public static void main(String[] args) {
        File xsd = new File("menu_config.xsd");
        File xml = new File("menu_config.xml");

        try {
            SchemaFactory factory = SchemaFactory.newInstance(
                XMLConstants.W3C_XML_SCHEMA_NS_URI
            );
            Schema schema = factory.newSchema(xsd);
            Validator validator = schema.newValidator();

            validator.validate(new StreamSource(xml));
            System.out.println("xml is valid");
        }
        catch (SAXException|IOException e) {
            System.out.println("Reason: " + e.getLocalizedMessage());
        }
    }
}



參考資料:
XML 結構描述項目 - MSDN
XML Schema Tutorial W3Schools
2012-03-16 22:55

[PHP] 檢查 XML 文件結構

利用 SimpleXML 去檢查 XML 結構是否符合規格,為了讓這個程式可以多用途,採用了一個基準文件的作為結構準則,依據裡面定義的節點跟屬性,去檢查文件是否符合基本要求的格式。

<?php

/**檢查 XML 文件結構
 * @param string $baseFilePath 基準結構文件
 * @param string $checkFilePath 待檢查文件
 * @return bool 當結構與基準文件相符合時則回傳 true,否則是 false
 * */
function checkXmlFileStructure($baseFilePath,$checkFilePath){
    /*開啟 Base File*/
    if(!file_exists($baseFilePath)){ return false; }
    $base = simplexml_load_file($baseFilePath);
    if($base===false){ return false; }

    /*開啟 Check File*/
    if(!file_exists($checkFilePath)){ return false; }
    $check = simplexml_load_file($checkFilePath);
    if($check===false){ return false; }

    /*比較起始點的名稱*/
    if($base->getName() != $check->getName()){ return false; }

    /*比較結構*/
    return checkXmlStructure($base,$check);
}

/**檢查 XML 結構
 * @param SimpleXMLElement $base 基準結構物件
 * @param SimpleXMLElement $check 待檢查 XML 物件
 * @return bool 當結構與基準物件相符合時則回傳 true,否則是 false
 * */
function checkXmlStructure($base,$check){
    /*檢查屬性*/
    foreach ($base->attributes() as $name => $baseAttr){
        /*必要的屬性不存在*/
        if(!isset($check->attributes()->$name)){ return false; }
    }

    /*當沒有子節點時,則檢查對象也不能有子節點*/
    if(count($base->children())==0){
        return (count($check->children())==0);
    }

    /*將檢查對象的子節點分群*/
    $checkChilds = array();
    foreach($check->children() as $name => $child){
        $checkChilds[$name][] = $child;
    }

    /*檢查子節點*/
    $checked = array();
    foreach($base->children() as $name => $baseChild){
        /*跳過已經檢查的子節點*/
        if(in_array($name, $checked)){ continue; }
        $checked[] = $name;

        /*檢查必要的子節點是否存在*/
        if(empty($checkChilds[$name])){ return false; }

        foreach ($checkChilds[$name] as $child){
            /*遞迴檢查子節點*/
            if( !checkXmlStructure($baseChild, $child) ){ return false; }
        }
    }

    return true;
}


/*==============================================================================*/

if(isset($_SERVER['argv'])){
    parse_str(preg_replace('/&[\-]+/','&',join('&',$_SERVER['argv'])), $_GET);

    if(empty($_GET['base_file']) || empty($_GET['check_file'])){
        echo "Run: ".basename(__FILE__)." base_file=base.xml check_file=check.xml\n"; exit(1);
    }

    exit( checkXmlFileStructure($_GET['base_file'],$_GET['check_file']) ? 0 : 1);

}else{
    if(empty($_GET['base_file']) || empty($_GET['check_file'])){
        echo "Run: ".basename(__FILE__)."?base_file=base.xml&check_file=check.xml<br />"; exit;
    }

    echo( checkXmlFileStructure($_GET['base_file'],$_GET['check_file']) ? '1' : '0');
}


使用方式(shell)
php check_xml_file_structure.php base_file=base.xml check_file=check.xml

if [ "j$?" != "j0" ]; then
    echo "Run Error"
fi


測試範例 1
base_1.xml
<?xml version="1.0" encoding="UTF-8"?>
<items>
    <item>
        <Category>Category文字</Category>
        <Title>Title文字</Title>
    </item>
</items>

check_1.xml
<?xml version="1.0" encoding="UTF-8"?>
<items>
    <item>
        <Category>Category文字</Category>
        <Title>Title文字</Title>
    </item>
    <item>
        <Category>Category文字</Category>
        <Title>Title文字</Title>
        <Description>Description文字</Description>
    </item>
</items>


測試範例 2
base_2.xml
<?xml version="1.0" encoding="UTF-8"?>
<items>
    <item category="Category文字" Title="Title文字"/>
</items>

check_2.xml
<?xml version="1.0" encoding="UTF-8"?>
<items>
    <item category="Category文字" Title="Title文字" Description="Description文字" />
    <item category="Category文字" Title="Title文字" />
    <item category="Category文字" Title="Title文字" Description="Description文字" />
</items>
2012-02-01 14:05

[PHP] 用 SoapServer 建立 Microsoft Office Research Service

這裡我用 Webservice Helper 來處理 WSDL 的問題,所以範例也是 Base 在 Webservice Helper 上面,在開始前請檢查是否有 php_soapphp_xsl 這兩個套件。


為了相容於 Research Service 的名稱空間,在輸出入的定義上需要在包一層資料類型,所以需要以下的類型定義:
StatusResponse.class.php
<?php
/**
 * Return object to Status method
 */
class StatusResponse {
    /** @var string */
    public $StatusResult;
}

Registration.class.php
<?php
/**
 * Input object to Registration method
 */
class Registration {
    /** @var string */
    public $registrationXml;
}

RegistrationResponse.class.php
<?php
/**
 * Return object to Registration method
 */
class RegistrationResponse {
    /** @var string */
    public $RegistrationResult;
}

Query.class.php
<?php
/**
 * Input object to Query method
 */
class Query {
    /** @var string */
    public $queryXml;
}

QueryResponse.class.php
<?php
/**
 * Return object to Query method
 */
class QueryResponse {
    /** @var string */
    public $QueryResult;
}


接著是建立 Web Service 的 Method,主要定義 Registration 跟 Query 這兩個 Method 就可以了,Registration 是用在新增 Research Service 到 Research Pane 時會呼叫的 Method,主要是提供 Research Pane 所需要的 Service 資訊。
而 Query 則是真正再處理資料查詢的 Method,而 QueryResponse 中的 domain 及 QueryId 必需與 QueryXml 中所給的相同,不然 Client 端會無法辨識回傳結果。
<?php
/**
 * Microsoft Office Research Service
 *
 */

class MsOfficeResearch {

    /**
     * Entry point to test if server is alive. Will return 'ONLINE' or 'OFFLINE'
     * @param void
     * @return StatusResponse
     */
    function Status() {
        $result = new StatusResponse;
        $result->StatusResult = 'ONLINE';
        return $result;
    }


    /**
     * Basic registration entry point
     * @param Registration $registrationXml
     * @return RegistrationResponse
     */
    public function Registration($registrationXml) {
//      debugDump('registrationXml: '.$request->registrationXml);

        $dom = new DOMDocument();

        $proUpdate = $dom->createElementNS("urn:Microsoft.Search.Registration.Response",'ProviderUpdate');
        $proUpdate->appendChild( new DOMElement('Status',"SUCCESS") );

        $providers = $proUpdate->appendChild( new DOMElement('Providers') );
        $provider = $providers->appendChild( new DOMElement('Provider') );
        $provider->appendChild( new DOMElement('Id',"{62E1D68D-E1C4-4CC5-9D0C-D4B7999C4B77}") );
        $provider->appendChild( new DOMElement('Name',"Research Service") );
        $provider->appendChild( new DOMElement('QueryPath',"http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']) );
        $provider->appendChild( new DOMElement('RegistrationPath',"http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']) );
        $provider->appendChild( new DOMElement('Type',"SOAP") );
        $provider->appendChild( new DOMElement('Revision',"1") );

        $services = $provider->appendChild( new DOMElement('Services') );
        $service = $services->appendChild( new DOMElement('Service') );
        $service->appendChild( new DOMElement('Id',"{0297CD20-047F-4256-0104-000004040001}") );
        $service->appendChild( new DOMElement('Name',"Research Service Name") );
        $service->appendChild( new DOMElement('Description',"Research Service Description") );
        $service->appendChild( new DOMElement('Copyright',"") );
        $service->appendChild( new DOMElement('Display',"On") );
        $service->appendChild( new DOMElement('Category',"RESEARCH_GENERAL") );

        $response = new RegistrationResponse;
        $response->RegistrationResult = $dom->saveXML($proUpdate);
        return $response;
    }



    /**
     * Basic entrypoint for Query
     * @param Query $queryXml
     * @return QueryResponse
     */
    function Query($queryXml) {
        if(is_object($queryXml)){ $queryXml = $queryXml->queryXml; }
//      debugDump('queryXml: '.$queryXml);

        /*解析請求的 XML*/
        $dom = new DOMDocument();
        $dom->loadXML($queryXml);
        $domain = $dom->getElementsByTagName('Query')->item(0)->getAttribute('domain');
        $queryId = $dom->getElementsByTagName('QueryId')->item(0)->nodeValue;

        /*建立返回的結構*/
        $packet = $dom->createElementNS("urn:Microsoft.Search.Response",'ResponsePacket');
        $packet->setAttribute('revision',"1");
        $response = $packet->appendChild( new DOMElement('Response') );
        $response->setAttribute('domain', $domain );
        $response->appendChild( new DOMElement('QueryId', $queryId) );
        $range = $response->appendChild( new DOMElement('Range') );
        $results = $range->appendChild( new DOMElement('Results') );
        $content = $results->appendChild( new DOMElement('Content',"","urn:Microsoft.Search.Response.Content") );

        /*請求查詢*/
        $status = "ERROR_NO_RESULTS_FOUND";
        $queryText = trim( $dom->getElementsByTagName('QueryText')->item(0)->nodeValue );
        if(!empty($queryText)){
//          debugDump($queryText);
            $line = $content->appendChild( new DOMElement('P') );
            $line->nodeValue = htmlspecialchars($queryText, ENT_QUOTES);
            $status = "SUCCESS";
        }

        $response->appendChild( new DOMElement('Status',$status) );

        /*設定回傳結構*/
        $response = new QueryResponse;
        $response->QueryResult = $dom->saveXML($packet);
        return $response;
    }

}


關於資料交換的 XML 格式如下:
Registration Response XML
<ProviderUpdate xmlns='urn:Microsoft.Search.Registration.Response'>
    <Status>SUCCESS</Status>
    <Providers><Provider>
        <Id>{88686849-2DD9-474d-9300-778E3336FA77}</Id>
        <Name>EpgTools</Name>
        <QueryPath>http://localhost/service.php</QueryPath>
        <RegistrationPath>http://localhost/service.php</RegistrationPath>
        <Type>SOAP</Type>
        <Revision>1</Revision>
        <Services><Service>
            <Id>63d351db-d12e-448b-8541-9f794e1ec977</Id>
            <Name>Research Service Name</Name>
            <Data>1031/1033/4</Data>
            <Description>Research Service Description</Description>
            <AboutPath>helpId:553713956</AboutPath>
            <Copyright>All content Copyright (c) 2003.</Copyright>
            <Display>On</Display>
            <Category>RESEARCH_GENERAL</Category>
            <OptionsPath></OptionsPath>
            <Parental>Unsupported</Parental>
        </Service></Services>
    </Provider></Providers>
</ProviderUpdate>

Query XML
<QueryPacket xmlns="urn:Microsoft.Search.Query" revision="1" build="(11.0.5606)">
    <Query domain="{6E3B8AA1-5131-403E-AEF3-E7AFC2E88557}">
        <QueryId>{5A4FD162-DB71-45BC-8721-F059D28947B3}</QueryId>
        <OriginatorId>{F6FF7BE0-F39C-4ddc-A7D0-09A4C6C647A5}</OriginatorId>
        <SupportedFormats>
            <Format revision="1">urn:Microsoft.Search.Response.Document:Document</Format>
            <Format revision="1">urn:Microsoft.Search.Response.Content:Content</Format>
            <Format revision="1">urn:Microsoft.Search.Response.Form:Form</Format>
        </SupportedFormats>
        <Context>
            <QueryText type="STRING" language="zh-tw">test</QueryText>
            <LanguagePreference>zh-tw</LanguagePreference>
            <Requery></Requery>
        </Context>
        <Range id="result"></Range>
        <OfficeContext xmlns="urn:Microsoft.Search.Query.Office.Context" revision="1">
            <UserPreferences>
                <ParentalControl>false</ParentalControl>
            </UserPreferences>
            <ServiceData>EWATW</ServiceData>
            <ApplicationContext>
                <Name>Microsoft Office</Name>
                <Version>(11.0.5606)</Version>
                <SystemInformation>
                    <SkuLanguage>zh-tw</SkuLanguage>
                    <LanguagePack>zh-tw</LanguagePack>
                    <InterfaceLanguage>zh-tw</InterfaceLanguage>
                    <Location>TW</Location>
                </SystemInformation>
            </ApplicationContext>
            <QueryLanguage>zh-tw</QueryLanguage>
            <KeyboardLanguage>zh-tw</KeyboardLanguage>
        </OfficeContext>
        <Keywords xmlns="urn:Microsoft.Search.Query.Office.Keywords" revision="1">
            <QueryText>test</QueryText>
            <Keyword>
                <Word>test</Word>
            </Keyword>
        </Keywords>
    </Query>
</QueryPacket>

Query Response XML
<ResponsePacket xmlns="urn:Microsoft.Search.Response" revision="1">
    <Response domain="{6e3b8aa1-5131-403e-aef3-e7afc2e88557}">
        <QueryId>{5A4FD162-DB71-45BC-8721-F059D28947B3}</QueryId>
        <Range><Results>
            <Content xmlns="urn:Microsoft.Search.Response.Content">
                <any />
            </Content>
        </Results></Range>
        <Status>SUCCESS</Status>
    </Response>
</ResponsePacket>


範例下載:
SearchService.zip


參考資料:
Serveur SOAP en PHP 5 pour "Microsoft Office Research Service"
The Definitive Hello World Custom Research Service Tutorial
Microsoft.Search.Response.Content Schema Documentation
2010-10-07 18:04

讓 Eclipse Task tag 能用在任何文件類型上

之前為了找能夠在 SQL File 中使用 Task tag 套件花了不少時間,最後發現 Mylyn 的套件中有一個針對所有專案下 DTD 跟 XML 的 Task tag 功能,索性利用這個功能讓 SQL 也支援 Task tag。

因為這個功能只支援 XML 格式的註解 <!-- 至 -->,所以只要巧妙的利用這個特性就可以達到我們要的功能。


首先在『內容類型 → DTD』中加入 *.sql 。



再來在 SQL file 的起始處加入 -- <!--



在結尾處加上 -- -->



開啟『專案 → 內容』啟用 Task Tags,並將 『Filters』中的 XML 取消。



我希望可以標出所有資料表的定義,所以在這裡我加入 TABLE 這個關鍵字。



接著就可以看到很快樂的結果了。



當然在 Task View 中也會列出所有的標記。
2010-07-16 17:29

[PHP] 取得 Weather Underground 即時氣象

如果你需要即時的氣象資訊,找 Weather Underground 是一個不錯的選擇,每30分鐘更新一次,再加上提供很方便 XML 資料連結,唯一感到美中不足的就是沒有多國語言的支持。

<?php
// ?query=[觀測點名稱],例如: Taoyuan Air Base , Taipei
$xml = simplexml_load_file(
    "http://api.wunderground.com/auto/wui/geo/WXCurrentObXML/index.xml?query=RCSS"
);

// 氣象圖示
foreach ($xml->icons->children() as $icon_set) {
    if($icon_set['name']=='Contemporary'){
        echo $icon_set->icon_url;
    }    
}
/* 
圖示造型種類:
    Default
    Smiley
    Helen
    Generic
    Old School
    Cartoon
    Mobile
    Simple
    Contemporary
    Dunkin' Donuts    
*/

echo "氣象狀況:",$xml->weather,"\n";

echo "溫度:",$xml->temp_c,"°C\n";

echo "相對濕度:",$xml->relative_humidity,"\n";

echo "風向:",$xml->wind_dir,"\n";

echo "風速:",$xml->wind_mph,"MPH\n";
echo "風速:每小時",round($xml->wind_mph*1.6093),"公里\n";
echo "風速:每秒",round($xml->wind_mph*0.447028),"公尺\n";

echo "海平面氣壓:",$xml->pressure_mb,"百帕\n";

echo "高溫指數:",$xml->heat_index_c,"°C\n";

echo "風寒指數:",$xml->windchill_c,"°C\n";

echo "水凝點:",$xml->dewpoint_c,"°C\n";

echo "能見度:",$xml->visibility_km,"公里\n";

echo "觀測時間:",date(
    'Y-m-d H:i',
    strtotime($xml->observation_time_rfc822)
),"\n";

/* 
thunderstorm rain = 雷雨
showers rain = 驟雨
light showers rain = 小驟雨

Cloudy = 多雲
Flurries = 小雪
Fog = 霧
Haze = 陰霾
Mostly Cloudy = 多雲時陰
Mostly Sunny = 晴時多雲
Partly Cloudy = 局部多雲
Partly Sunny = 多雲時晴
Freezing Rain = 凍雨
Rain = 雨
Sleet = 冰雹
Snow = 雪
Sunny = 晴朗
Unknown = 未知
Overcast = 陰天
Scattered Clouds = 疏雲 
*/


參考資料:
台灣各地-氣象觀測點
API - XML - WunderWiki

PHP: simplexml_load_file - Manual
2010-05-03 14:40

[ActionScript] 讀取 XML 資料格式

1.資料欄位以子節點方式載入與解析

<!-- load_1.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<xmltest>
<parentnode>
<id>1</id>
<name>小明</name>
<date>2010-10-10</date>
</parentnode>
<parentnode>
<id>2</id>
<name>小王</name>
<date>2010-5-15</date>
</parentnode>
</xmltest>


/*建立 XML()*/
LoadXml_1 = new XML();

/*捨棄只包含空白字元的文字節點*/
LoadXml_1.ignoreWhite=true;

/*載入完成時所執行的程式*/
LoadXml_1.onLoad = function(){
articleList = this.firstChild.childNodes;
var txt = "";
for (i=0; i<articleList.length; i++) {
elementList = articleList[i].childNodes;
for (j=0; j<elementList.length; j++) {
elementTag = elementList[j];
switch(elementTag.nodeName){
case "id":
txt += elementTag.firstChild.nodeValue+',';
break;
case "name":
txt += elementTag.firstChild.nodeValue+',';
break;
case "date":
txt += elementTag.firstChild.nodeValue+',';
break;
}
}
txt += '\n';
}

trace(txt); /*顯示載入的資料*/
}

/*開始載入 load_1.xml*/
LoadXml_1.load("load_1.xml");



2.資料欄位以屬性方式載入與解析

<!-- load_2.xml -->
<?xml version="1.0" encoding="utf-8"?>
<xmltest>
<parentnode id="1" name="小明" date="2010-10-10" />
<parentnode id="2" name="小王" date="2010-5-15" />
</xmltest>


/*建立 XML()*/
LoadXml_2 = new XML();

/*捨棄只包含空白字元的文字節點*/
LoadXml_2.ignoreWhite=true;

/*載入完成時所執行的程式*/
LoadXml_2.onLoad = function(success) {
var articleList = this.firstChild.childNodes;
var txt = "";
for (i=0; i<articleList.length; i++){
txt += articleList[i].attributes.id+','
+articleList[i].attributes.name+','
+articleList[i].attributes.call+','
+articleList[i].attributes.channel+"\n";
}

trace(txt);/*顯示載入的資料*/
};

/*開始載入 load_2.xml*/
LoadXml_2.load("load_2.xml");




參考資料:
Flash CS4 Professional ActionScript 2.0 - XML
2010-01-26 22:12

[JavaScript] 解析 XML 字串(IE / FF)

String.prototype.toXmlDom=function(){
    var dom=null;
    if (window.DOMParser){
        dom = (new DOMParser()).parseFromString(this, "text/xml");
    }else{
        dom=new ActiveXObject("microsoft.XMLDOM");
        dom.async=false;
        dom.loadXML(this);
    } 
    return dom;
}

xmlDom = xmlStr.toXmlDom();


我做了一些測試,在 Firefox 中就像一般的 DOM Element 一樣操作就可以了。

但在 IE 中所解析出來的 XML 是以 Object 的方式處理,只能使用 IE 所提供的方法操作,而且有些 tag node 會無法取得,如 <date>。

參考來源:
javascript读取xml(firefox与ie兼容)
XML DOM Parser
2009-12-21 15:11

Blogger 文章匯入的格式

Blogger 可以接受 Atom 的格式匯入
至於 RSS 的格式就要去找轉換器轉成 Atom 才可以匯入

以下是 Blogeer 匯入時的最簡化的格式

<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet
href="http://www.blogger.com/styles/atom.css"
type="text/css"?
>
<feed xmlns='http://www.w3.org/2005/Atom'
xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'
xmlns:georss='http://www.georss.org/georss'
>
<id>tag:blogger.com,1999:blog-4</id>
<generator version='7.00' uri='http://www.blogger.com'>Blogger</generator>

<entry>
<id>tag:blogger.com,1999:blog-4.post-2</id>
<published>2009-12-19T23:39:20.281+08:00</published>
<title type='text'>標題</title>
<content type='html'>文章內容</content>
<category scheme='http://www.blogger.com/atom/ns#' term='標籤1'/>
<category scheme='http://www.blogger.com/atom/ns#' term='標籤2'/>
</entry>

<entry>
<id>tag:blogger.com,1999:blog-4.post-2</id>
<published>2009-12-19T23:39:20.281+08:00</published>
<title type='text'>標題</title>
<content type='html'>文章內容</content>
<category scheme='http://www.blogger.com/atom/ns#' term='標籤1'/>
<category scheme='http://www.blogger.com/atom/ns#' term='標籤2'/>
</entry>

</feed>
  • generator:產生器識別,Blogger 只接受自己的標示
  • id:可以重複,但必須符合格式
  • published:發佈時間,格式為 ISO8601
  • title:文章標題
  • content:文章內文,可以允許換行符號"\n",內文的 HTML 必須實體逸出
  • category:標籤
2009-03-29 08:09

iGoogle 小工具製作心得

iGoogle 小工具主要是以 XML 為主體,再加上 HTML、CSS 及 JavaScript 所組成的,基本上只要會後面三種語言,要開發 iGoogle 小工具是非常快樂的一件事。

在這裡我只做一些的教學及心得分享,詳細的規範及 API 說明,請察看官方網站 Google 小工具 API 開發人員指南,開發指南裡面寫的很清楚,還有很多的範例可以參考。

心得建議:
  • 開發時建議 XML 的檔名不要太正式,iGoogle 的平台會 cache XML,造成檢視上會出現不一致情況,等到要發佈時再取一個正式的檔名,避免不必要的問題發生。
  • 如果要使用 session 和 cookie 做登入驗證的話,最好使用 <iframe> 去處理,會比較容易達成且安全問題也比較少。
  • 在 ModulePrefs 中的 category 屬性也記得加上去,在官方的開發人員指南中並沒有說明,共有:
    • politics
    • tools
    • funandgames
    • lifestyle
    • finance
    • communication
    • 等...。

  • 多利用[便條簿]做測試可以減少不少時間。
  • 測試時最好在 iGoogle 上另開一個[分頁],免得自己原本常用的小工具被打亂。
  • 在測試的[分頁]中最好加上[開發人員小工具]這個小工具去管理 cache 問題。

小工具範例:

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs
title="單位換算"
description="更方便的介面處理單位制度上的換算"
directory_title="單位換算"
author="Jax"
author_email="weskerjax+feed@gmail.com"
thumbnail=
"http://weskerjax.googlepages.com/unit_converter_thumbnail.png"
screenshot=
"http://weskerjax.googlepages.com/unit_converter_screenshot.png"
title_url="http://jax-work-archive.blogspot.com/"
category="tools"
height="300">
<Locale lang="zh-tw" country="TW"/>
<Require feature="tabs"/>
<Require feature="dynamic-height"/>
</ModulePrefs>
<UserPref
name="type"
display_name="預設開啟的頁籤"
default_value="長度"
datatype="enum">
<EnumValue value="長度"/>
<EnumValue value="重量"/>
<EnumValue value="面積"/>
<EnumValue value="體積"/>
</UserPref>
<Content type="html">
<![CDATA[
<style type="text/css">
.JContent table{
margin-top:5px;
width:100%;
}
.JContent th{
background-color:#99CCFF;
padding-top:5px;
}
.JContent label{
text-align:center;
padding:3px;
display:block;
font-size:12px;
}
.JContent label input{
display:block;
text-align:left;
line-height:1.1em;
font-size:11px;
width:95%;
}
</style>
<script type="text/javascript">
var prefs = new _IG_Prefs(__MODULE_ID__);
function set_event__MODULE_ID__(tabId){
var inputs=_gel(tabId).getElementsByTagName('input');
for (var i=0, j=inputs.length; i<j; i++){
el=inputs[i];
/*設定 onkeyup 時處理單位換算*/
el.onkeyup=function(){
this.value=this.value.match(/[0-9]+[\.]?[0-9]*/);
var rate=this.getAttribute('rate');
var value=parseFloat(this.value)/parseFloat(rate);

var table=this;
while(table.tagName!="TABLE"){table=table.parentNode;}

var inputs=table.getElementsByTagName('input');
for (var i=0, j=inputs.length; i<j; i++){
chg=inputs[i];
r=chg.getAttribute('rate');
if(r==rate){continue;}

if(this.value){chg.value=value*parseFloat(r);}
else{chg.value='';}
};
};
/*設定 onfocus 選取所有文字*/
el.onfocus=function(){this.select()};
};
/*讓小工具能夠自行調整大小*/
_IG_AdjustIFrameHeight();
}
function init() {
/*建立頁籤並選定預選頁籤*/
var tabs = new _IG_Tabs(__MODULE_ID__,prefs.getString("type"));
tabs.addTab("長度","J_length",set_event__MODULE_ID__);
tabs.addTab("重量","J_weight",set_event__MODULE_ID__);
tabs.addTab("面積","J_area",set_event__MODULE_ID__);
tabs.addTab("體積","J_volume",set_event__MODULE_ID__);
}
_IG_RegisterOnloadHandler(init);/*載入時呼叫的事件處理常式*/
</script>
<div class="JContent" id="J_length">
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<td><label>公尺<input rate="1" type="text" /></label></td>
<td><label>公里<input rate="0.001" type="text" /></label></td>
<td><label>海里<input rate="0.00053996" type="text" /></label></td>
<tr>
<td><label>英吋<input rate="39.370" type="text" /></label></td>
<td><label>英呎<input rate="3.2808" type="text" /></label></td>
<td><label>英碼<input rate="1.0936" type="text" /></label></td>
</tr>
<td><label>台尺<input rate="3.3003" type="text" /></label></td>
<td><label>市里<input rate="2e-3" type="text" /></label></td>
<td><label>市引<input rate="0.03" type="text" /></label></td>
</tr>
</table>
</div>
<div class="JContent" id="J_weight">
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<td><label>公斤<input rate="1" type="text" /></label></td>
<td><label>公克<input rate="1e+3" type="text" /></label></td>
<td><label>公噸<input rate="1e-3" type="text" /></label></td>
</tr>
<tr>
<td><label>英磅<input rate="2.2046" type="text" /></label></td>
<td><label>盎司<input rate="35.273" type="text" /></label></td>
<td><label>英噸<input rate="9.8421e-4" type="text" /></label></td>
</tr>
<tr>
<td><label>美噸<input rate="0.0011023" type="text" /></label></td>
<td><label>格令<input rate="15432" type="text" /></label></td>
<td><label>克拉<input rate="5000" type="text" /></label></td>
</tr>
<tr>
<td><label>台斤<input rate="1.6667" type="text" /></label></td>
<td><label>台兩<input rate="26.667" type="text" /></label></td>
<td><label>市擔<input rate="0.02" type="text" /></label></td>
</tr>
</table>
</div>
<div class="JContent" id="J_area">
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<td><label>公畝<input rate="100.00" type="text" /></label></td>
<td><label>公頃<input rate="1" type="text" /></label></td>
<td><label>平方公里<input rate="0.01" type="text" /></label></td>
</tr>
<tr>
<td><label>平方英寸<input rate="155e+5" type="text" /></label></td>
<td><label>平方英尺<input rate="107640" type="text" /></label></td>
<td><label>平方碼<input rate="11960" type="text" /></label></td>
</tr>
<tr>
<td><label>英畝<input rate="2.4711" type="text" /></label></td>
<td><label>平方英里<input rate="0.003861" type="text" /></label></td>
<td> </td>
</tr>
</table>
</div>
<div class="JContent" id="J_volume">
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<td><label>立方公尺<input rate="1" type="text" /></label></td>
<td><label>公升<input rate="1e+3" type="text" /></label></td>
<td><label>毫升<input rate="1e+6" type="text" /></label></td>
</tr>
<tr>
<td><label>英國加侖<input rate="219.97" type="text" /></label></td>
<td><label>液體加侖<input rate="264.17" type="text" /></label></td>
<td><label>固體加侖<input rate="227.02" type="text" /></label></td>
</tr>
</table>
</div>
]]>
</Content>
</Module>


範例預覽:

範例原始檔:unit_converter.xml


第一個開發的小工具:
2009-03-04 21:52

製作 sitemap 的心得

最近在為網站製作 sitemap 產生器,花了半小時去看 sitemaps.org - 通訊協定,這跟 Google 網站管理員工具的定義是一樣的,基本上 sitemap 的格式是很簡單的,詳細說明請察看官方文件。

網路上有很多 sitemap 產生器,但產生出來的結果不如期望,為了做出更好的 sitemap 清單,我就自己作網站的 sitemap 產生器。


需要注意的小細節:
  1. sitemap 索引與 sitemap 中 url 引入的 xsd 是不一樣的
  2. 注意檔案大小 10MB 及筆數的上限 50,000 筆 URL。
  3. 檔案如果很大最好用 gzip 壓縮,壓縮率會有 10 倍以上的落差。
  4. 一定要用驗證器確認格式是否正確,在壓縮前請先確認格式,驗證器無法解析 gzip
  5. 一份 sitemap 中的 priority 值不能全部一樣,Google 會出現 warning。
  6. 如果檔案已經封存不會變動,在 changefreq 的值最好設定為 never ,這樣會得到較好的文件索引。


Sitemap:
<?xml version='1.0' encoding='UTF-8'?>
<urlset 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9"
    url="http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
    xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
>
   <url>
      <loc>http://www.example.com/</loc>
      <lastmod>2005-01-01</lastmod>
      <changefreq>monthly</changefreq>
      <priority>0.8</priority>
   </url>
   <url>
      <loc>http://www.example.com/catalog?item=12&desc=v_hawaii</loc>
      <lastmod>2005-01-01</lastmod>
      <changefreq>monthly</changefreq>
      <priority>0.8</priority>
   </url>
   <url>
      <loc>http://www.example.com/catalog?item=83&desc=v_usa</loc>
      <lastmod>2005-01-01</lastmod>
      <changefreq>monthly</changefreq>
      <priority>0.8</priority>
   </url>
</urlset>


Sitemap 索引檔:
<?xml version='1.0' encoding='UTF-8'?>
<sitemapindex 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9"
    url="http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd"
    xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
>
   <sitemap>
      <loc>http://www.example.com/sitemap1.xml.gz</loc>
      <lastmod>2004-10-01T18:23:17+00:00</lastmod>
   </sitemap>
   <sitemap>
      <loc>http://www.example.com/sitemap2.xml.gz</loc>
      <lastmod>2005-01-01</lastmod>
   </sitemap>
</sitemapindex>


Sitemap 驗證器:
Google Sitemap(s) Validator


參考文章:
Peter的部落格: Google Sitemaps 教學
網站登錄與提交sitemap(Yahoo!) @ 神鵰蝦
2008-01-27 15:33

架站使用 UTF-8 要檢查的項目

一開始最基本的就是環境設定,Server 對於文字的編碼設定,這也是最重要的。

關於 Apache Server 的設定:
在 /etc/httpd/conf/httpd.conf(Red Hat) 或 /etc/apache2/conf.d/charset(Ubuntu) 中開啟對 UTF-8 編碼的設定:
AddDefaultCharset utf-8

關於 Mysql Server 的設定:
在使用 script 進行新增/修改時記得在 script 檔中加入:
SET NAMES 'utf8';
在 PHP 存取前也應該先宣告編碼方式:
mysql_query("SET NAMES 'UTF8'");

在建立文字欄位(TEXT, VARCHAR, ...)時也必須定義文字的編碼方式:
CHARACTER SET utf8 COLLATE utf8_unicode_ci

在編寫網頁文件時,除了要注意檔案是否使用 UTF-8 編碼外,還要記得加上編碼宣告,因為解讀器並沒有那麼聰明,沒辦法準確的辨別檔案的編碼方式,所以請一定要加上編碼宣告。

關於 HTML 文件的宣告:
<meta equiv="Content-Type" content="text/html; charset=UTF-8">

關於 XML 文件的宣告:
<?xml version="1.0" encoding="UTF-8"?>

關於 PHP 文件的宣告:
header('Content-type: text/html; charset=utf-8');

參考文章:UTF-8 checklist - soledad penadés