الباور شيل لتحليل XML: قراءة والتحقق

XML موجود في كل مكان. على الرغم من استخدامه المزعج لعلامات الزوايا، إلا أن تنسيق XML ما زال يستخدم على نطاق واسع. ملفات التكوين، وتغذيات RSS، وملفات Office (الـ ‘x’ في .docx) هي مجرد قائمة جزئية. استخدام PowerShell لتحليل ملفات XML خطوة أساسية في رحلتك مع PowerShell.

سيعرض هذا البرنامج التعليمي كيفية تحليل ملفات XML باستخدام PowerShell والتحقق من صحتها. سيأخذك ذلك من الصفر إلى البطل في جميع جوانب الحصول على البيانات XML وتقييمها. ستحصل على أدوات ستساعدك في التحقق من سلامة بيانات XML ووقف البيانات المعيبة مباشرة عند بوابة النصوص الخاصة بك!

المتطلبات

لمتابعة المواد المقدمة، يجب أن تكون لديك:

  • إصدار PowerShell 3.0 وما فوق. تم إنشاء الأمثلة على PowerShell v5.1 لنظام التشغيل Windows
  • Notepad++، Visual Studio Code أو محرر نصوص آخر يفهم XML.

تحليل عناصر PowerShell XML بـ Select-Xml

لنغطي أولاً واحدة من أكثر الطرق شيوعًا وأسهل الطرق لاستخدام PowerShell لتحليل XML وهي باستخدام Select-Xml. يسمح لك cmdlet Select-Xml بتوفير ملف XML أو سلسلة بيانات XML مع “مرشح” معروف باسم XPath لاستخراج معلومات محددة.

XPath هو سلسلة من أسماء العناصر. يستخدم بناء بنية “مماثلة للمسار” لتحديد العقد وتصفح العقد في مستند XML.

لنقل أن لديك ملف XML يحتوي على مجموعة من الحواسيب وترغب في استخدام PowerShell لتحليل هذا الملف. كل حاسوب لديه عناصر متنوعة مثل الاسم وعنوان IP وعنصر Include للتضمين في تقرير.

العنصر هو جزء من مستند XML بوجود علامة افتتاح وعلامة إغلاق ، ربما مع بعض النص بينهما ، مثل <Name>SRV-01</Name>

<Computers>
	<Computer>
		<Name>SRV-01</Name>
		<Ip>127.0.0.1</Ip>
		<Include>true</Include>
	</Computer>	
	<Computer>
		<Name>SRV-02</Name>
		<Ip>192.168.0.102</Ip>
		<Include>false</Include>
	</Computer>	
	<Computer>
		<Name>SRV-03</Name>
		<Ip>192.168.0.103</Ip>
		<Include>true</Include>
	</Computer>	
</Computers>

تود استخدام PowerShell لتحليل ملف XML هذا للحصول على أسماء الحواسيب. للقيام بذلك ، يمكنك استخدام أمر Select-Xml.

في الملف أعلاه ، تظهر أسماء الحواسيب في النص الداخلي (InnerXML) لعنصر Name.

InnerXML هو النص بين علامتي العنصر.

للعثور على أسماء الحواسيب ، يجب عليك أولاً توفير XPath المناسب (/Computers/Computer/Name). ستعيد بنية XPath هذه فقط عقد Name تحت عناصر Computer. ثم للحصول فقط على InnerXML لكل عنصر Name ، استخدم خاصية Node.InnerXML على كل عنصر بواسطة حلقة ForEach-Object.

Select-Xml -Path C:\Work\computers-elm.xml -XPath '/Computers/Computer/Name' | ForEach-Object { $_.Node.InnerXML }

استخدام PowerShell لتحليل سمات XML بواسطة Select-Xml

الآن دعونا نتناول هذه المشكلة في العثور على أسماء الحواسيب من زاوية مختلفة. هذه المرة، بدلاً من تمثيل وصفي الحواسيب باستخدام عناصر XML ، يتم تمثيلها باستخدام سمات XML.

السمة هي جزء مفتاح/قيمة مثل name="SRV-01". تظهر السمات دائمًا داخل العلامة الافتتاحية، مباشرة بعد اسم العلامة.

أدناه ملف XML مع وصفي الحواسيب الممثلة بسمات. يمكنك الآن رؤية كل وصف كسمة بدلاً من عنصر.

<Computers>
	<Computer name="SRV-01" ip="127.0.0.1" include="true" />
	<Computer name="SRV-02" ip="192.168.0.102" include="false" />
	<Computer name="SRV-03" ip="192.168.0.103" include="true" />
</Computers>

نظرًا لأن كل وصف الآن هو سمة، قم بضبط مسار XPath قليلاً للعثور فقط على عناصر الكمبيوتر. ثم، باستخدام cmdlet ForEach-Object مرة أخرى، اعثر على قيمة السمة الاسم.

Select-Xml -Path C:\Work\computers-attr.xml -XPath '/Computers/Computer' | ForEach-Object { $_.Node.name }

وبالفعل، يأتي هذا أيضًا بنفس النتائج: SRV-01، SRV-02 و SRV-03:

Reading data using Select-Xml

في كلتا الحالتين، سواء كنت تقرأ العناصر أو السمات، فإن بناء جملة Select-Xml معقد: فهو يجبرك على استخدام المعلمة XPath، ثم توجيه النتيجة إلى حلقة، وأخيرًا البحث عن البيانات تحت خاصية Node.

لحسن الحظ، تقدم PowerShell طريقة أكثر راحة وبديهية لقراءة ملفات XML. يتيح لك PowerShell قراءة ملفات XML وتحويلها إلى كائنات XML.

ذات صلة: استخدام تسارعات أنواع بيانات PowerShell لتسريع البرمجة

تحويل سلاسل XML إلى كائنات

طريقة أخرى لاستخدام PowerShell لتحليل XML هي تحويل ذلك XML إلى كائنات. أسهل طريقة للقيام بذلك هي باستخدام تسريع النوع [xml].

عن طريق إضافة بادئة لأسماء المتغيرات باستخدام [xml] ، يقوم PowerShell بتحويل النص العادي الأصلي لـ XML إلى كائنات يمكنك العمل بها.

[xml]$xmlElm = Get-Content -Path C:\Work\computers-elm.xml
[xml]$xmlAttr = Get-Content -Path C:\Work\computers-attr.xml

قراءة عناصر الكائنات XML

الآن كل من المتغيرات $xmlElm و $xmlAttr هما كائنات XML تمكنك من الرجوع إلى الخصائص عن طريق استخدام النقطة. ربما تحتاج إلى العثور على عنوان IP لكل عنصر كمبيوتر. نظرًا لأن ملف XML هو كائن ، يمكنك القيام بذلك بالرجوع إلى عنصر IP ببساطة.

$xmlElm.Computers.Computer.ip

بدءًا من إصدار PowerShell 3.0 ، يحصل الكائن XML على قيمة السمة بنفس الصيغة المستخدمة لقراءة النص الداخلي للعنصر. وبالتالي ، يتم قراءة قيم عناوين IP من ملف السمات بنفس الصيغة تمامًا مثل ملف العناصر.

قراءة سمات XML

باستخدام نفس الصيغة بالنقطة ، يمكنك قراءة سمات XML على الرغم من الاختلافات في هيكل XML.

$xmlElm.Computers.Computer.ip
$xmlAttr.Computers.Computer.ip

والنتائج أدناه تظهر أن كلاهما حصل على نفس البيانات ، كل واحد من ملفه المقابل:

PowerShell to Parse XML : Reading XML Attributes

علاوة على ذلك ، مع الكائن ، بمجرد تحميله في الذاكرة ، حتى تحصل على التكمل التلقائي لإكمال التبويب إذا كنت تستخدم PowerShell ISE. على سبيل المثال كما هو موضح أدناه.

IntelliSense and tab completion for XML object

التكرار من خلال بيانات XML

بمجرد أن تستطيع قراءة ملفات XML مباشرة إلى كائن XML (باستفادة من تسريع النوع [xml]) ، فلديك كل قوة الكائنات في PowerShell.

قل، على سبيل المثال، إذا كنت مطالبًا بتكرار جميع الحواسيب التي تظهر في ملف XML بسمة include=”true” لفحص حالة اتصالها. يُظهر الكود أدناه كيف يمكن القيام بذلك.

يكون البرنامج النصي هو:

  • قراءة الملف وتحويله إلى كائن XML.
  • التكرار من خلال الحواسيب ذات الصلة للحصول على حالة اتصالها.
  • وأخيرًا، إرسال كائن النتيجة الناتج إلى الخط السير.
 ## تحويل نص الملف إلى كائن XML
 [xml]$xmlAttr = Get-Content -Path C:\Work\computers-attr.xml

 ## تكرار عبر مجموعة الحواسيب التي تحمل include="true"
 $xmlAttr.Computers.Computer | Where-Object include -eq 'true' |  ForEach-Object {
     ## التحقق مما إذا كانت الحاسوب الحالي متصلًا بالإنترنت
     if(Test-Connection -ComputerName $_.ip -Count 1 -Quiet)
     {
         $status = 'Connection OK'
     }
     else
     {
         $status = 'No Connection'
     }

     ## إخراج كائن النتيجة
     [pscustomobject]@{
         Name = $_.name
         Ip = $_.ip
         Status = $status
     }
 }

ويتم عرض نتائج البرنامج أعلاه كما يلي:

Connection status results

مخططات XML

في القسم السابق، رأيت ملفي XML مختلفين يمثلان مجموعة بيانات بطريقتين مختلفتين. تلك الطرق تُسمى مخططات XML. يحدد مخطط XML الكتل البنائية القانونية لـ مستند XML معين:

  • أسماء العناصر والسمات التي يمكن أن تظهر في ذلك المستند المحدد.
  • عدد وترتيب العناصر الفرعية.
  • أنواع البيانات للعناصر والسمات.

يحدد المخطط بشكل أساسي هيكل XML.

التحقق من صحة بيانات XML

ملف XML قد يحتوي على بناء بيانات صحيح (سيتذمر محررات مثل Notepad++ إذا لم يكن كذلك)، ومع ذلك قد لا تتوافق البيانات مع متطلبات المشروع. هنا تأتي دورة المخطط. عندما تعتمد على بيانات XML، يجب عليك التأكد من أن جميع البيانات صالحة وفقًا للمخطط المحدد.

آخر شيء تريده هو اكتشاف أخطاء البيانات أثناء التشغيل، 500 سطراً في منتصف النص. قد يكون قد قام بعض العمليات اللاعادية على نظام الملفات والسجل بحلول تلك الفترة.

فكيف يمكنك التحقق مسبقًا من صحة البيانات؟ دعنا نرى أولاً بعض أنواع الأخطاء الممكنة.

الأخطاء الممكنة في بيانات XML

بشكل عام، تنتمي الأخطاء التي تم العثور عليها في ملفات XML إلى إحدى الفئتين؛ أخطاء البيانات الوصفية وأخطاء في البيانات نفسها.

أخطاء البيانات الوصفية في XML

هذا الملف MorePeople.xml أدناه، صحيح بناءً بشكل مثالي من الناحية الصحيحة. يمكنك أن ترى أدناه أن الملف يحتوي على عنصر واحد People (العنصر الجذر) مع ثلاثة عناصر Person في الداخل. هذه الهيكلة مقبولة تمامًا. لكن لديها استثناء واحد، هل تستطيع أن تراه؟

<People>
	<Person Name="Debra" County="Canada" IsAdmin="true" />
	<Person Name="Jacob" Country="Israel" IsAdmin="true" />
	<Person Name="Olivia" Country="Cyprus" IsAdmin="false" />
</People>

لا تقلق إذا لم تستطع، فهو مخفي فقط. المشكلة تكمن في العنصر الداخلي الأول:

ما كان يجب أن يكون Country تم كتابته بشكل خاطئ، وتم تحويل Canada إلى County.

أخطاء في بيانات XML

بعد إصلاح مشكلة Country في MorePeople.xml، تسللت مشكلة أخرى:

<People>
	<Person Name="Debra" Country="Canada" IsAdmin="yes" />
	<Person Name="Jacob" Country="Israel" IsAdmin="true" />
	<Person Name="Olivia" Country="Cyprus" IsAdmin="false" />
</People>

البيانات الوصفية، أي العناصر والسمات، على ما يرام. فما هو الخطأ؟ هذه المرة، المشكلة، مرة أخرى على سطر الأول، هي في أحد القيم. قرر شخص ما أن نعم بمثابة بديل كافٍ لـ صحيح – لكن الكود مثل الذي بالأسفل سيفشل في الحصول على العنصر الأول حيث يبحث عن صحيح، وليس عن نعم:

$peopleXml.People.Person | Where-Object IsAdmin -eq 'true'

إنشاء مخطط XML

الآن بعد أن تعرفت على أنواع الأخطاء التي قد تحدث، حان الوقت لنرى كيف يساعد ملف المخطط. الخطوة الأولى هي إنشاء ملف بيانات عينة. يمكن أن تكون العينة أصغر مثال وتحتوي على شيء بسيط ولا تحتوي سوى على عنصر داخلي واحد. للأمثلة أعلاه، دعنا ننشئ ملف عينة مثل هذا People.xml:

<People>
	<Person Name="Jeff" Country="USA" IsAdmin="true" />
</People>

الآن قم ببناء وظيفة PowerShell أدناه واستخدمها مع بيانات العينة لإنشاء مخطط .xsd.

function New-XmlSchema
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory)]
        [ValidateScript({ Test-Path -Path $_ })]
        [ValidatePattern('\.xml')]
        [string]$XmlExample
    ) 

    $item = Get-Item $XmlExample
    $dir = $item.Directory
    $name = $item.Name
    $baseName = $item.BaseName

    
## بناء مسار المخطط بواسطة استبدال '.xml' بـ '.xsd'

    $SchemaPath = "$dir\$baseName.xsd"

    try
    {
        $dataSet = New-Object -TypeName System.Data.DataSet
        $dataSet.ReadXml($XmlExample) | Out-Null
        $dataSet.WriteXmlSchema($SchemaPath)
        
        
## عرض ملف المخطط الناتج

        Get-Item $SchemaPath
    }
    catch
    {
        $err = $_.Exception.Message
        Write-Host "Failed to create XML schema for $XmlExample`nDetails: $err" -ForegroundColor Red
    }
}

انسخ الوظيفة إلى بيئة التطوير المتكاملة ISE الخاصة بك أو محرر PowerShell المفضل لديك، حمّلها في الذاكرة، واستخدمها لإنشاء المخطط. مع الوظيفة المحمّلة، الكود لإنشاء المخطط هو سطر واحد فقط:

New-XmlSchema -XmlExample 'C:\Work\People.xml'

سيظهر النتائج المسار إلى المخطط الذي تم إنشاؤه حديثًا:

Creating XML schema from a sample data file

استخدام ملف المخطط للتحقق من صحة بياناتك

انظر إلى الموقع المحدد في النتائج أعلاه. إذا كان الملف .xsd موجوداً هناك، فأنت على الطريق الصحيح لرؤية التحقق من الصحة في العمل. لخطوة التأكيد، استخدم الوظيفة أدناه:

function Test-XmlBySchema
{
    [CmdletBinding()]
    [OutputType([bool])]
    param
    (
        [Parameter(Mandatory)]
        [ValidateScript({ Test-Path -Path $_ })]
        [ValidatePattern('\.xml')]
        [string]$XmlFile,
        [Parameter(Mandatory)]
        [ValidateScript({ Test-Path -Path $_ })]
        [ValidatePattern('\.xsd')]
        [string]$SchemaPath
    )

    try
    {
        [xml]$xml = Get-Content $XmlFile
        $xml.Schemas.Add('', $SchemaPath) | Out-Null
        $xml.Validate($null)
        Write-Verbose "Successfully validated $XmlFile against schema ($SchemaPath)"
        $result = $true
    }
    catch
    {
        $err = $_.Exception.Message
        Write-Verbose "Failed to validate $XmlFile against schema ($SchemaPath)`nDetails: $err"
        $result = $false
    }
    finally
    {
        $result
    }
}

قم بتحميل الوظيفة في الذاكرة، واستخدمها للتحقق من MorePeople.xml من خلال مثالي الخطأ. لتشغيل التحقق، استخدم الأمر أدناه:

Test-XmlBySchema -XmlFile 'C:\Work\MorePeople.xml' -SchemaPath 'C:\Work\People.xsd' -Verbose

النتائج الفعلية تعتمد على محتوى MorePeople.xml.

دعنا نرى مثالين. لاحظ أنه عندما يكون MorePeople.xml خاليًا من الأخطاء، ستُرجع الوظيفة أعلاه True.

Validation success

عندما يحتوي ملف MorePeople.xml على بيانات خاطئة (تمت كتابة المفتاح Country بشكل خاطئ كـ County)، ستُرجع الوظيفة تفاصيل فشل مع عودة False.

Validation failure – wrong attribute name detected

كما يمكنك رؤية، الخطأ المحدد في الإخراج النصي المفصل مفيد للغاية: يشير إلى ملف الجاني ويشير إلى المكون الدقيق فيه حيث حدثت المشكلة.

ضبط دقيق لمخطط التحقق

دعنا نلقي نظرة على ملف المخطط، ثم نرى كيف يمكننا تحسينه أكثر.

المخطط الذي أنشأته New-XmlSchema افتراضياً هو كالتالي:

<?xml version="1.0" standalone="yes"?>
<xs:schema id="People" xmlns="" xmlns:xs="<http://www.w3.org/2001/XMLSchema>" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="People" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="Person">
          <xs:complexType>
            <xs:attribute name="Name" type="xs:string" />
            <xs:attribute name="Country" type="xs:string" />
            <xs:attribute name="IsAdmin" type="xs:string" />
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

المخطط الافتراضي أعلاه جيد، ولكنه ليس مثاليًا. فعلاً، قد قام بالتقاط الخطأ مع السمة Country. ولكن، إذا تركت المخطط كما هو، في حالة عدم تحقق التوقعات الأخرى التي قد تكون لديك – فلن يتم الإبلاغ عن هذه المشاكل كأخطاء من قبل التحقق Test-XmlBySchema. دعونا نحل هذا.

الجدول أدناه يقدم بعض الحالات التي لا تعتبر أخطاء تحقق وستمر دون اكتشافها بواسطة Test-XmlBySchema. في كل صف، تُظهر العمود الأيمن كيفية تغيير النظام يدويًا لإضافة الدعم اللازم للحماية.

A modified version of the schema file, with all protections added, is shown right after the table.

إضافة إعداد إلى المخطط الافتراضي – أمثلة

Required Behavior Relevant setting on the schema file
At least one Person element Set the minOccurs value of the Person element to 1
Make Name, Country and IsAdmin attributes mandatory Add use=”required” to each of these attributes declaration
Allow only true/false values for IsAdmin Set type=”xs:boolean” for the IsAdmin declaration
Allow only Country names between 3 and 40 characters Use the xs:restriction (see detailed explanation after the schema text)
<?xml version="1.0" standalone="yes"?>
<xs:schema id="People" xmlns="" xmlns:xs="<http://www.w3.org/2001/XMLSchema>" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="People" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="Person">
          <xs:complexType>
            <xs:attribute name="Name" type="xs:string" use="required" />
	    <xs:attribute name="Country" use="required">
	      <xs:simpleType>
		<xs:restriction base="xs:string">
		  <xs:minLength value="3"/>
		  <xs:maxLength value="40"/>
		</xs:restriction>
	      </xs:simpleType>
	    </xs:attribute>	
            <xs:attribute name="IsAdmin" type="xs:boolean" use="required" />
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

مع القيد البولياني في مكانه لسمة IsAdmin في المثال، يجب أن تكون قيمتها حروف صغيرةصحيحة أو خاطئة.

التحقق من طول السلسلة باستخدام xs:restriction

يعتبر التحقق من طول السلسلة أمرًا معقدًا قليلاً. لذا، على الرغم من أنه يظهر أعلاه كجزء من المخطط المعدل، يستحق المزيد من التركيز.

العنصر الأصلي في المخطط لسمة Country (بعد إضافة use=”required” يدويًا) هو كما يلي:

<xs:attribute name="Country" type="xs:string" use="required" />

لإضافة حماية الطول، يجب أن تضيف عنصر <xs:simpleType>، وداخله، <xs:restriction base="xs:string">. يحتوي هذا القيد بدوره على الحدود المطلوبة المعلن عنها على xs:minLength و xs:minLength.

بعد كل هذه التغييرات، نموذج xs:attribute النهائي قد نما من سطر واحد إلى عقد ضخم من 8 أسطر:

<xs:attribute name="Country">
  <xs:simpleType>
	<xs:restriction base="xs:string">
	  <xs:minLength value="3"/>
	  <xs:maxLength value="40"/>
	</xs:restriction>
  </xs:simpleType>
</xs:attribute>

إذا لم يدور رأسك بعد الشرح أعلاه، فقد حققت الحق في رؤية التحقق في العمل. للقيام بذلك، دعونا نقصد قيمة Canada عن عمد إلى مقطعين: Ca

مع اسم البلد القصير في مكانه، و MorePeople.xml محفوظ، أنت الآن جاهز لتشغيل أمر التحقق أدناه:

Test-XmlBySchema -XmlFile 'C:\Work\MorePeople.xml' -SchemaPath 'C:\Work\People.xsd' -Verbose

والنتائج تظهر بالفعل أن المخطط المعقد قد قام بعمله:

A string length error detected by the schema validation

يمكن أن تزداد تعقيدات التحقق من صحة مخطط XML والتحقق من أي نمط يمكن أن تفكر فيه، خاصةً عندما يتم دمجه مع التعابير العادية.

Source:
https://adamtheautomator.com/powershell-parse-xml/