2014-10-08 3 views
1

이 질문은 많은 변형에서 볼 수 있지만 그 중 어떤 것도 제 상황을 언급하지는 않습니다.비표준 XML wsman 데이터를 PHP로 객체에로드하기

나는 WSMan을 사용하여 데이터를 가져오고, 그 결과 sudo-xml의 종류로 출력됩니다. 비표준 속성이 너무 많아서 "진짜"xml이라고 생각하지 않습니다. 문제는 PHP 내에서 출력물을 객체로 참조 할 수 있어야한다는 것입니다. 그래서 지금은 str_replace를 많이 사용하고 있습니다. 이 문제는 비표준 형식이 다른 경우 (어떤 경우에는 <KeyID xsi:nil="true"/>과 같은 것을 반환 할 것입니다. 다른 경우에는 <CMCIP xsi:nil="true"/>과 같을 수 있습니다), 내가가는 다른 속성을 모두 예측하는 것은 어렵습니다 simplexml_load_string을 사용하여 개체로 가져 오기 전에 변수를 고려하고 추출해야합니다.

모든 단순함에 대한 내 질문 : 객체에 비표준 XML을로드하는 방법이 있습니까? 다음은 xml 데이터의 샘플입니다. 여기에서 다루고있는 광기를 알 수 있습니다.

<?xml version="1.0" encoding="UTF-8"?> 
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsen="http://schemas.xmlsoap.org/ws/2004/09/enumeration"> 
    <s:Header> 
    <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To> 
    <wsa:Action>http://schemas.xmlsoap.org/ws/2004/09/enumeration/EnumerateResponse</wsa:Action> 
    <wsa:RelatesTo>uuid:3ae2d181-04f0-14f0-8002-89040b5d1500</wsa:RelatesTo> 
    <wsa:MessageID>uuid:43a291ab-04f0-14f0-8073-b516f1d9bed4</wsa:MessageID> 
    </s:Header> 
    <s:Body> 
    <wsen:EnumerateResponse> 
     <wsen:EnumerationContext>439c90e9-04f0-14f0-8072-b516f1d9bed4</wsen:EnumerationContext> 
    </wsen:EnumerateResponse> 
    </s:Body> 
</s:Envelope> 
<?xml version="1.0" encoding="UTF-8"?> 
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsen="http://schemas.xmlsoap.org/ws/2004/09/enumeration" xmlns:n1="http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_SystemView" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <s:Header> 
    <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To> 
    <wsa:Action>http://schemas.xmlsoap.org/ws/2004/09/enumeration/PullResponse</wsa:Action> 
    <wsa:RelatesTo>uuid:3af0a1eb-04f0-14f0-8003-89040b5d1500</wsa:RelatesTo> 
    <wsa:MessageID>uuid:43a41fe8-04f0-14f0-8074-b516f1d9bed4</wsa:MessageID> 
    </s:Header> 
    <s:Body> 
    <wsen:PullResponse> 
     <wsen:Items> 
     <n1:DCIM_SystemView> 
      <n1:AssetTag/> 
      <n1:BIOSReleaseDate>11/20/2013</n1:BIOSReleaseDate> 
      <n1:BIOSVersionString>2.1.3</n1:BIOSVersionString> 
      <n1:BaseBoardChassisSlot>NA</n1:BaseBoardChassisSlot> 
      <n1:BatteryRollupStatus>1</n1:BatteryRollupStatus> 
      <n1:BladeGeometry>255</n1:BladeGeometry> 
      <n1:BoardPartNumber>061P35A00</n1:BoardPartNumber> 
      <n1:BoardSerialNumber>CN70163231007K</n1:BoardSerialNumber> 
      <n1:CMCIP xsi:nil="true"/> 
      <n1:CPLDVersion>1.0.3</n1:CPLDVersion> 
      <n1:CPURollupStatus>1</n1:CPURollupStatus> 
      <n1:ChassisModel/> 
      <n1:ChassisName>Main System Chassis</n1:ChassisName> 
      <n1:ChassisServiceTag>REMOVED</n1:ChassisServiceTag> 
      <n1:ChassisSystemHeight>2</n1:ChassisSystemHeight> 
      <n1:DeviceDescription>System</n1:DeviceDescription> 
      <n1:ExpressServiceCode>33088672189</n1:ExpressServiceCode> 
      <n1:FQDD>System.Embedded.1</n1:FQDD> 
      <n1:FanRollupStatus>1</n1:FanRollupStatus> 
      <n1:HostName/> 
      <n1:InstanceID>System.Embedded.1</n1:InstanceID> 
      <n1:LastSystemInventoryTime>20140928010936.000000+000</n1:LastSystemInventoryTime> 
      <n1:LastUpdateTime>20140220171215.000000+000</n1:LastUpdateTime> 
      <n1:LicensingRollupStatus>1</n1:LicensingRollupStatus> 
      <n1:LifecycleControllerVersion>2.1.0</n1:LifecycleControllerVersion> 
      <n1:Manufacturer>Dell Inc.</n1:Manufacturer> 
      <n1:MaxCPUSockets>2</n1:MaxCPUSockets> 
      <n1:MaxDIMMSlots>24</n1:MaxDIMMSlots> 
      <n1:MaxPCIeSlots>6</n1:MaxPCIeSlots> 
      <n1:MemoryOperationMode>OptimizerMode</n1:MemoryOperationMode> 
      <n1:Model>PowerEdge R720xd</n1:Model> 
      <n1:NodeID>F7852V1</n1:NodeID> 
      <n1:PSRollupStatus>1</n1:PSRollupStatus> 
      <n1:PlatformGUID>3156324f-c0c6-3580-3810-00374c4c4544</n1:PlatformGUID> 
      <n1:PopulatedCPUSockets>2</n1:PopulatedCPUSockets> 
      <n1:PopulatedDIMMSlots>8</n1:PopulatedDIMMSlots> 
      <n1:PopulatedPCIeSlots>2</n1:PopulatedPCIeSlots> 
      <n1:PowerCap>598</n1:PowerCap> 
      <n1:PowerCapEnabledState>3</n1:PowerCapEnabledState> 
      <n1:PowerState>2</n1:PowerState> 
      <n1:PrimaryStatus>1</n1:PrimaryStatus> 
      <n1:RollupStatus>1</n1:RollupStatus> 
      <n1:ServerAllocation xsi:nil="true"/> 
      <n1:ServiceTag>REMOVED</n1:ServiceTag> 
      <n1:StorageRollupStatus>1</n1:StorageRollupStatus> 
      <n1:SysMemErrorMethodology>6</n1:SysMemErrorMethodology> 
      <n1:SysMemFailOverState>NotInUse</n1:SysMemFailOverState> 
      <n1:SysMemLocation>3</n1:SysMemLocation> 
      <n1:SysMemMaxCapacitySize>1572864</n1:SysMemMaxCapacitySize> 
      <n1:SysMemPrimaryStatus>1</n1:SysMemPrimaryStatus> 
      <n1:SysMemTotalSize>65536</n1:SysMemTotalSize> 
      <n1:SystemGeneration>12G Monolithic</n1:SystemGeneration> 
      <n1:SystemID>1320</n1:SystemID> 
      <n1:SystemRevision>0</n1:SystemRevision> 
      <n1:TempRollupStatus>1</n1:TempRollupStatus> 
      <n1:UUID>4c4c4544-0037-3810-8035-c6c04f325631</n1:UUID> 
      <n1:VoltRollupStatus>1</n1:VoltRollupStatus> 
      <n1:smbiosGUID>44454c4c-3700-1038-8035-c6c04f325631</n1:smbiosGUID> 
     </n1:DCIM_SystemView> 
     </wsen:Items> 
     <wsen:EndOfSequence/> 
    </wsen:PullResponse> 
    </s:Body> 
</s:Envelope> 
+0

안녕 폴, 답장을 보내 주셔서 감사합니다,하지만 당신은 자세히 설명해 주시겠습니까? 나는이 비누 설명서를보고 있지만, 지금까지는 이렇게 보이는 것이 보이지 않는다. 내가 뭘 놓치고 있니? 죄송합니다. 무언가에 대해서는 XML 이외의 내용은 다루지 않았습니다. 나는 정상이 어떤 종류인지 깨닫지 못했습니다 ... – Ethan

답변

2

응답/출력으로 반환되는 것은 여러 XML 문서의 연결입니다. 귀하의 예에서는 두 가지입니다.

이것은 유효한 XML이 아니지만 드문 일도 아닙니다.

그래서 당신이해야 할 모든 문서를 분할하고 처리 할 필요가있는 하나를 선택하는 것입니다 (귀하의 예를 두 번째에) :

$split = preg_split('~\Q<?xml version="1.0" encoding="UTF-8"?>\E\R~u', $sequenced_xml, 2, PREG_SPLIT_NO_EMPTY); 
$xml = simplexml_load_string($split[1]); 

이제 XML 문서 END_LINK하면 관심을 가지고 관심이 있다면 SOAP 응답을 구문 분석하는 방법에 대한 다른 많은 대답을 제안 할 수 있습니다. 잘못된 형식의 XML (실제로 연결된 XML 형식의 문서 시퀀스)이 더 이상 존재하지 않습니다.

나머지는 네임 스페이스를 처리합니다.

일부 포인터 :

$soap = 'http://www.w3.org/2003/05/soap-envelope'; 
$body = $xml->children($soap)->Body; 

... 배열로 모든 열거 된 항목 :

$wsen = 'http://schemas.xmlsoap.org/ws/2004/09/enumeration'; 
$xml->registerXPathNamespace('wsen', $wsen); 
$items = $body->xpath('.//wsen:*/*[not(namespace-uri(.) = namespace-uri(..))]'); 

등 등

...을 SOAP 봉투 몸을 얻기 위해 .

당신이 당신의 대답에 준 자신의 코드 예제에 대한 참고 사항 : 당신이 어떤 네임 스페이스의 요소 이름을 찾고 있다면, 당신은 local-name()와 XPath는이 작업을 수행 할 수 있습니다

$pullitem = 'ServiceTag'; 
$try  = $xml->xpath(sprintf("//*[local-name(.)='%s']", $pullitem)); 

printf("pullitem '%s' has been foun in the following namespaces:\n", $pullitem); 
foreach ($try as $element) { 
    $nsURI = dom_import_simplexml($element)->namespaceURI; 
    printf(" - %s\n", $nsURI); 
} 

그 5 개 정도의 개별 xpath 호출을 남겨 둡니다.

네임 스페이스에 대해 신경 쓰지 않으려면 DOMDocument를 사용하여 각 항목의 "그 중 하나"가 될 것으로 기대합니다. 각각의 결과에 대해 SimpleXMLElement를 만듭니다. 그것의 자신의 새 문서 : 그것은 새로운 SimpleXMLElement에 대한 네임 스페이스로 요소의 자신의 네임 스페이스를 박았

/** 
* create a new SimpleXMLElement out of an existing one 
* 
* @param SimpleXMLElement $item 
* 
* @return SimpleXMLElement 
*/ 
function simplexml_export_element(SimpleXMLElement $item) { 
    $doc = new DOMDocument(); 
    $node = $doc->importNode(dom_import_simplexml($item), true); 
    $node = $doc->appendChild($node); 
    return simplexml_load_string($doc->saveXML($doc->documentElement), get_class($item), 0, $node->namespaceURI); 
} 

이러한 도우미 루틴이 도움이됩니다. 이를 통해 동일한 네임 스페이스의 하위 항목에 직접 액세스 할 수 있습니다. 코드를 계속 사용하면이 "기본"네임 스페이스를 특별히 신경 쓸 필요가 없습니다.

예 :

$split = preg_split('~\Q<?xml version="1.0" encoding="UTF-8"?>\E\R~u', $sequenced_xml, 2, PREG_SPLIT_NO_EMPTY); 

$xml = new SimpleXMLElement($split[1]); 

$soap = 'http://www.w3.org/2003/05/soap-envelope'; 
$body = $xml->children($soap)->Body; 

$wsen = 'http://schemas.xmlsoap.org/ws/2004/09/enumeration'; 
$xml->registerXPathNamespace('wsen', $wsen); 

$enumerated = $body->xpath('.//wsen:*/*[not(namespace-uri(.) = namespace-uri(..))]'); 
$enumerated = array_map('simplexml_export_element', $enumerated); 

foreach ($enumerated as $item) { 
    echo $item->getName(), "\n"; 
    foreach ($item as $key => $value) { 
     printf(" - %s: %s\n", $key, $value); 
    } 
} 

출력이 여전히 경우에 도움이된다

DCIM_SystemView 
- AssetTag: 
- BIOSReleaseDate: 11/20/2013 
- BIOSVersionString: 2.1.3 
- BaseBoardChassisSlot: NA 
- BatteryRollupStatus: 1 
- BladeGeometry: 255 
- BoardPartNumber: 061P35A00 
- BoardSerialNumber: CN70163231007K 
- CMCIP: 
- CPLDVersion: 1.0.3 
- CPURollupStatus: 1 
- ChassisModel: 
- ChassisName: Main System Chassis 
- ChassisServiceTag: REMOVED 
- ChassisSystemHeight: 2 
- DeviceDescription: System 
- ExpressServiceCode: 33088672189 
- FQDD: System.Embedded.1 
- FanRollupStatus: 1 
- HostName: 
- InstanceID: System.Embedded.1 
- LastSystemInventoryTime: 20140928010936.000000+000 
- LastUpdateTime: 20140220171215.000000+000 
- LicensingRollupStatus: 1 
- LifecycleControllerVersion: 2.1.0 
- Manufacturer: Dell Inc. 
- MaxCPUSockets: 2 
- MaxDIMMSlots: 24 
- MaxPCIeSlots: 6 
- MemoryOperationMode: OptimizerMode 
- Model: PowerEdge R720xd 
- NodeID: F7852V1 
- PSRollupStatus: 1 
- PlatformGUID: 3156324f-c0c6-3580-3810-00374c4c4544 
- PopulatedCPUSockets: 2 
- PopulatedDIMMSlots: 8 
- PopulatedPCIeSlots: 2 
- PowerCap: 598 
- PowerCapEnabledState: 3 
- PowerState: 2 
- PrimaryStatus: 1 
- RollupStatus: 1 
- ServerAllocation: 
- ServiceTag: REMOVED 
- StorageRollupStatus: 1 
- SysMemErrorMethodology: 6 
- SysMemFailOverState: NotInUse 
- SysMemLocation: 3 
- SysMemMaxCapacitySize: 1572864 
- SysMemPrimaryStatus: 1 
- SysMemTotalSize: 65536 
- SystemGeneration: 12G Monolithic 
- SystemID: 1320 
- SystemRevision: 0 
- TempRollupStatus: 1 
- UUID: 4c4c4544-0037-3810-8035-c6c04f325631 
- VoltRollupStatus: 1 
- smbiosGUID: 44454c4c-3700-1038-8035-c6c04f325631 

희망.

+0

와우, 그건 훌륭한 설명입니다. 슈퍼 도움이됩니다. 이 일을 할 시간을 내 주셔서 정말로 감사드립니다. :) 나는 내가 사용하고있는 함수와 비슷한 것을 했었고, 당신이 여기에 제시 한 것과 같은 것들을 더 효율적으로 사용하기 위해 취할 것입니다. 내 모자가 너에게 간다! – Ethan

1

@Paul Crovella에게 의견을 보내 주셔서 감사합니다. 실제로이 사실을 알게되었습니다. 나는 많은 것을 배웠다. 어쨌든, 해결책은 여러 가지의 조합으로 끝 맺었습니다. 이 게시물 그러나, 가장 도움이되었다 : 나는 작업을 얻었는지, 내가 날 위해 구문 분석하는 함수를 작성 결국 호기심 당신의 사람들을 위해

How do I read SOAP reply Envelope by PHP

. 귀하의 convinience 들어, 그것은 아래에 위치해 있습니다. 잘만되면 이것은 내가 있었던 같은 물건을 찾고있는 길의 누군가 다른 사람을 도와 준다!

function pull_wsman_idrac($run_iDRAC_IP,$user,$pass,$namespace,$pullitem,$context="NULL"){ 
    //Example pull_wsman("10.10.10.10","root","calvin","DCIM_SystemView","ServiceTag") 
    //Possible namespaces are listed on the DCIM profile page on Dell's website. http://en.community.dell.com/techcenter/systems-management/w/wiki/1906.dcim-library-profile 
    //Namspaces used (primary) : DCIM_SystemView, DCIM_CPUView, DCIM_ControllerView, DCIM_VFlashView, DCIM_MemoryView, DCIM_PCIDeviceView, DCIM_NICView, DCIM_IDRACCARDView 
    $wsman_output = shell_exec("wsman enumerate http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/root/dcim/$namespace -h $run_iDRAC_IP -V -v -c dummy.cert -P 443 -u $user -p $pass -j utf-8 -y basic"); 
    $wsman_output = preg_replace('/\<\?xml version="1.0" encoding="UTF-8"\?\>/', '', $wsman_output); 
    $wsman_output = preg_replace('/\<\?xml version="1.0" encoding="utf-8"\?\>/', '', $wsman_output); 
    $wsman_output = trim($wsman_output); 
    $conv = <<<XML 
    <root> $wsman_output </root> 
    XML; 
    $xml = new SimpleXMLElement($conv); 
    $xml->registerXPathNamespace("s", "http://www.w3.org/2003/05/soap-envelope"); 
    $xml->registerXPathNamespace("wsa", "http://schemas.xmlsoap.org/ws/2004/08/addressing"); 
    $xml->registerXPathNamespace("wsen", "http://schemas.xmlsoap.org/ws/2004/09/enumeration"); 
    $xml->registerXPathNamespace("n1", "http://schemas.dell.com/wbem/wscim/1/cim-schema/2/$namespace"); 
    $xml->registerXPathNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance"); 
    if($context == "NULL"){ 
     $try = $xml->xpath("//s:$pullitem"); 
     if(!empty($try)){ $cpath="s"; goto gotit; } 
     $try = $xml->xpath("//wsa:$pullitem"); 
     if(!empty($try)){ $cpath="wsa"; goto gotit; } 
     $try = $xml->xpath("//wsen:$pullitem"); 
     if(!empty($try)){ $cpath="wsen"; goto gotit; } 
     $try = $xml->xpath("//n1:$pullitem"); 
     if(!empty($try)){ $cpath="n1"; goto gotit; } 
     $try = $xml->xpath("//xsi:$pullitem"); 
     if(!empty($try)){ $cpath="xsi"; goto gotit; } 
     gotit: 
     if(empty($cpath)){ return 0; } 
      else{ 
       $a = array(); 
       $i = 0; 
       foreach($try as $tried){ 
        foreach($tried->xpath("//n1:*") as $trys) { 
        $go = $trys->getName(); 
        //$i++; echo "$i : " . $go . "\n"; 
        $a[] = $go; 
       } 
      } 
      $a = array_unique($a); 
      return $a;  
     } 
    } 
    elseif($context !== "NULL"){ 
     $try = $xml->xpath("//$context:$pullitem"); 
     $a = array(); 
     foreach($try as $extract){ 
      $a[] = $extract; 
     } 
     if(!empty($a)){ 
      return $a; 
     } 
     else{ return 0; } 
    } 
}