首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 操作 XML 處理指令 (Processing Instruction, PI) 完整教學:建立、讀取、修改、刪除

     編輯:關於C#

什麼是處理指令 (PI)?

XML 處理指令以 <?target data?> 形式存在,供特定應用程式解讀,不屬於文件資料樹一部分。常見範例:

  • <?xml version="1.0" encoding="utf-8"?> (XML 宣告,特殊 PI)
  • <?xml-stylesheet href="style.xsl" type="text/xsl"?> (樣式表關聯)
  • <?mso-application progid="InfoPath.Document"?> (Office InfoPath 指示)

核心類別:System.Xml.XmlProcessingInstruction

屬性/方法說明
Target目標名稱 (如 xml-stylesheet、mso-application)
Value / Data資料字串 (如 href="style.xsl" type="text/xsl")
OwnerDocument所屬 XmlDocument

完整操作範例


using System;
using System.Xml;

public class XmlPiManager
{
    private readonly XmlDocument _doc;
    private readonly string _filePath;

    public XmlPiManager(string filePath)
    {
        _filePath = filePath;
        _doc = new XmlDocument { XmlResolver = null }; // 安全:禁用外部資源解析
        _doc.Load(filePath);
    }

    /// 
    /// 讀取指定 Target 的 PI 值
    /// 
    public string ReadPi(string target)
    {
        // XPath: processing-instruction('target')
        var node = _doc.SelectSingleNode($"/processing-instruction('{target}')");
        return (node as XmlProcessingInstruction)?.Value;
    }

    /// 
    /// 修改或建立 PI
    /// 
    public void SetPi(string target, string value)
    {
        var pi = _doc.SelectSingleNode($"/processing-instruction('{target}')") 
                 as XmlProcessingInstruction;

        if (pi != null)
        {
            pi.Value = value; // 直接修改 Value 即可
        }
        else
        {
            // 建立新 PI 並插入文件開頭 (XML 宣告之後)
            pi = _doc.CreateProcessingInstruction(target, value);
            // 找到第一個非 PI 節點之前插入
            XmlNode insertBefore = null;
            foreach (XmlNode n in _doc.ChildNodes)
            {
                if (n.NodeType != XmlNodeType.ProcessingInstruction && 
                    n.NodeType != XmlNodeType.XmlDeclaration)
                {
                    insertBefore = n;
                    break;
                }
            }
            if (insertBefore != null)
                _doc.InsertBefore(pi, insertBefore);
            else
                _doc.AppendChild(pi);
        }
        _doc.Save(_filePath);
    }

    /// 
    /// 刪除指定 Target 的 PI
    /// 
    public void RemovePi(string target)
    {
        var node = _doc.SelectSingleNode($"/processing-instruction('{target}')");
        if (node != null)
        {
            _doc.RemoveChild(node);
            _doc.Save(_filePath);
        }
    }

    /// 
    /// 列印所有 PI
    
    public void PrintAllPi()
    {
        foreach (XmlNode node in _doc.ChildNodes)
        {
            if (node.NodeType == XmlNodeType.ProcessingInstruction)
            {
                var pi = (XmlProcessingInstruction)node;
                Console.WriteLine($"Target: {pi.Target}, Value: {pi.Value}");
            }
        }
    }
}

// 使用範例
class Program
{
    static void Main()
    {
        var mgr = new XmlPiManager("config.xml");
        
        mgr.PrintAllPi();
        // Target: xml-stylesheet, Value: href="style.xsl" type="text/xsl"
        // Target: mso-application, Value: progid="InfoPath.Document"

        string style = mgr.ReadPi("xml-stylesheet");
        Console.WriteLine($"樣式表:{style}");

        mgr.SetPi("custom-pi", "data=123;mode=test");
        mgr.RemovePi("mso-application");
    }
}

XPath 查詢 PI 關鍵語法

查詢需求XPath 運算式
所有 PI/processing-instruction()
特定 Target/processing-instruction('target-name')
包含特定字串的 PI/processing-instruction()[contains(., 'href')]

XML 宣告特殊處理


// XML 宣告非標準 PI,屬性為 XmlDeclaration
var decl = _doc.FirstChild as XmlDeclaration;
if (decl != null)
{
    Console.WriteLine($"Version: {decl.Version}, Encoding: {decl.Encoding}, Standalone: {decl.Standalone}");
    // 修改編碼
    decl.Encoding = "utf-8";
    _doc.Save(_filePath);
}

命名空間與 PI

PI 不屬於任何命名空間,Target 名稱慣例使用 prefix-name 避免衝突 (如 mso-application、xml-stylesheet)。

效能與安全注意事項

  1. XmlResolver = null:防止 XXE (XML External Entity) 攻擊,禁用 DTD/外部實體解析。
  2. 大型 XML 檔案建議使用 XmlReader 串流讀取 PI,避免完整載入 DOM。
  3. 修改後 Save 會重寫整個檔案,大檔案考慮備份機制。

串流讀取 PI 範例 (低記憶體)


public static string ReadPiStreaming(string filePath, string target)
{
    using (var reader = XmlReader.Create(filePath, new XmlReaderSettings 
    { 
        XmlResolver = null, 
        IgnoreProcessingInstructions = false // 關鍵:預設忽略 PI,必須設 false
    }))
    {
        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.ProcessingInstruction && 
                reader.Name == target)
            {
                return reader.Value;
            }
        }
    }
    return null;
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved