2012-02-27 82 views
0

我需要使用PHP将PDF转换为XML的帮助。 有一些网站声称这样做。但他们为此收取费用。 我必须在PHP中编写我自己的代码。 作为PHP新手,我不知道如何处理这个任务。 因此,如果任何人有工作,PLZ帮助我。使用PHP将PDF转换为XML

任何帮助将不胜感激。

+1

哪些模式? 'XML'有点含糊 - 你会接受' [你的pdf的全部内容]'是否合理? – 2012-02-27 13:51:50

+0

Hi @Bobby, 感谢您的快速响应。 其实我想将PDF的内容转换为xml。 PDF内容可以是任何东西。 然后,我需要将该PDF转换为XML,然后将该XML数据插入到mysql数据库。 我想你的想法也将工作。 现在你告诉我,如果你的方法适用于我的案件或不。 即使它不,我可能能够从你的方法extraxt一些想法。 – 2012-02-27 14:15:40

+0

我的观点是,你需要更仔细地考虑你想做什么,并在你的问题中包括一些细节,以说明你为什么要这样做。由于PDF和XML在本质上是非常不同的格式,因此它们之间的转换非常困难。例如,您的PDF包含 - laregly格式的说明。相反,您的XML包含语义信息。您需要定义 - 不知何故 - 如何在两者之间进行映射。 – 2012-02-27 14:24:08

回答

0

PDF2HTML将转换为HTML或XML(使用-xml标志),但结果有点乱。你会得到很多关于文本片段位置的小块信息。你没有什么想要提取文本的段落或部分。您可能能够使用合适的XPath分离图像?

如果您确实需要段落或段落的文字,看来您必须启发式地进行。 Geert's blog有一个有趣的方法:

  1. 隔离文本在不同的区域(如页眉和页脚)运行
  2. 收集文本在同一“行”(这里忽略列)
  3. 翻译缩进层次运行(帮助发现列表,提供裸露表/列处理)
  4. 合并线的建立段落
+1

github上提供了代码最有趣的部分:https://github.com/grtjn/utilities/blob/master/enrich-pdf2html.xsl – grtjn 2014-03-18 06:24:46

0

PDFX可进行PDF到XML的转换,并可免费使用。这可能对您的情况有所帮助,因为它可以分别提取图片和标题等内容。

可以找到示例输入/输出here

usage页面包含一个简单的PHP client example

(披露:这是我的系统。)

+0

我们可以看到源代码吗?我很乐意将它用于一个项目,但将其托管在我的服务器上,这样我就可以保证正常运行。 – Charlie 2013-02-09 02:56:20

+0

目前还不是开源的,对不起。非常有信心的正常运行时间不会成为问题,但如果您想谈论事情,请随时与我们联系。 – 2013-03-23 20:52:29

+0

@AlexConstantin!这是没有更多的工作,你可以请再次检查? – atif 2016-11-06 05:06:24

0

你可以使用这个类来收杆PDF转换为字符串,比工作,这一点,=)

<?php class PDF2Text2 { 
var $multibyte = 4; // 
var $convertquotes = ENT_QUOTES; // 
var $showprogress = true; // 
var $filename = ''; 
var $decodedtext = ''; 

function setFilename($filename) { 
    // Reset 
    $this->decodedtext = ''; 
    $this->filename = $filename; 
} 

function output($echo = false) { 
    if($echo) echo $this->decodedtext; 
    else return $this->decodedtext; 
} 

function setUnicode($input) { 
    // 4 for unicode. But 2 should work in most cases just fine 
    if($input == true) $this->multibyte = 4; 
    else $this->multibyte = 2; 
} 

function decodePDF() { 
    // Read the data from pdf file 
    $infile = @file_get_contents($this->filename, FILE_BINARY); 
    if (empty($infile)) 
     return ""; 

    // Get all text data. 
    $transformations = array(); 
    $texts = array(); 

    // Get the list of all objects. 
    preg_match_all("#obj[\n|\r](.*)endobj[\n|\r]#ismU", $infile . "endobj\r", $objects); 
    $objects = @$objects[1]; 

    // Select objects with streams. 
    for ($i = 0; $i < count($objects); $i++) { 
     $currentObject = $objects[$i]; 

     // Prevent time-out 
     @set_time_limit(); 
     if($this->showprogress) { //        echo ". "; 
      flush(); ob_flush(); 
     } 

     // Check if an object includes data stream. 
     if (preg_match("#stream[\n|\r](.*)endstream[\n|\r]#ismU", $currentObject . "endstream\r", $stream)) { 
      $stream = ltrim($stream[1]); 
      // Check object parameters and look for text data. 
      $options = $this->getObjectOptions($currentObject); 

      if (!(empty($options["Length1"]) && empty($options["Type"]) && empty($options["Subtype"]))) 
      if ($options["Image"] && $options["Subtype"]) 
      if (!(empty($options["Length1"]) && empty($options["Subtype"]))) 
       continue; 

      // Hack, length doesnt always seem to be correct 
      unset($options["Length"]); 

      // So, we have text data. Decode it. 
      $data = $this->getDecodedStream($stream, $options); 

      if (strlen($data)) { 
       if (preg_match_all("#BT[\n|\r](.*)ET[\n|\r]#ismU", $data . "ET\r", $textContainers)) { 
        $textContainers = @$textContainers[1]; 
        $this->getDirtyTexts($texts, $textContainers); 
       } else 
        $this->getCharTransformations($transformations, $data); 
      } 
     } 
    } 

    // Analyze text blocks taking into account character transformations and return results. 
    $this->decodedtext = $this->getTextUsingTransformations($texts, $transformations); 
} 


function decodeAsciiHex($input) { 
    $output = ""; 

    $isOdd = true; 
    $isComment = false; 

    for($i = 0, $codeHigh = -1; $i < strlen($input) && $input[$i] != '>'; $i++) { 
     $c = $input[$i]; 

     if($isComment) { 
      if ($c == '\r' || $c == '\n') 
       $isComment = false; 
      continue; 
     } 

     switch($c) { 
      case '\0': case '\t': case '\r': case '\f': case '\n': case ' ': break; 
      case '%': 
       $isComment = true; 
       break; 

      default: 
       $code = hexdec($c); 
       if($code === 0 && $c != '0') 
        return ""; 

       if($isOdd) 
        $codeHigh = $code; 
       else 
        $output .= chr($codeHigh * 16 + $code); 

       $isOdd = !$isOdd; 
       break; 
     } 
    } 

    if($input[$i] != '>') 
     return ""; 

    if($isOdd) 
     $output .= chr($codeHigh * 16); 

    return $output; 
} 

function decodeAscii85($input) { 
    $output = ""; 

    $isComment = false; 
    $ords = array(); 

    for($i = 0, $state = 0; $i < strlen($input) && $input[$i] != '~'; $i++) { 
     $c = $input[$i]; 

     if($isComment) { 
      if ($c == '\r' || $c == '\n') 
       $isComment = false; 
      continue; 
     } 

     if ($c == '\0' || $c == '\t' || $c == '\r' || $c == '\f' || $c == '\n' || $c == ' ') 
      continue; 
     if ($c == '%') { 
      $isComment = true; 
      continue; 
     } 
     if ($c == 'z' && $state === 0) { 
      $output .= str_repeat(chr(0), 4); 
      continue; 
     } 
     if ($c < '!' || $c > 'u') 
      return ""; 

     $code = ord($input[$i]) & 0xff; 
     $ords[$state++] = $code - ord('!'); 

     if ($state == 5) { 
      $state = 0; 
      for ($sum = 0, $j = 0; $j < 5; $j++) 
       $sum = $sum * 85 + $ords[$j]; 
      for ($j = 3; $j >= 0; $j--) 
       $output .= chr($sum >> ($j * 8)); 
     } 
    } 
    if ($state === 1) 
     return ""; 
    elseif ($state > 1) { 
     for ($i = 0, $sum = 0; $i < $state; $i++) 
      $sum += ($ords[$i] + ($i == $state - 1)) * pow(85, 4 - $i); 
     for ($i = 0; $i < $state - 1; $i++) { 
      try { 
       if(false == ($o = chr($sum >> ((3 - $i) * 8)))) { 
        throw new Exception('Error'); 
       } 
       $output .= $o; 
      } catch (Exception $e) { /*Dont do anything*/ } 
     } 
    } 

    return $output; 
} 

function decodeFlate($data) { 
    return @gzuncompress($data); 
} 

function getObjectOptions($object) { 
    $options = array(); 

    if (preg_match("#<<(.*)>>#ismU", $object, $options)) { 
     $options = explode("/", $options[1]); 
     @array_shift($options); 

     $o = array(); 
     for ($j = 0; $j < @count($options); $j++) { 
      $options[$j] = preg_replace("#\s+#", " ", trim($options[$j])); 
      if (strpos($options[$j], " ") !== false) { 
       $parts = explode(" ", $options[$j]); 
       $o[$parts[0]] = $parts[1]; 
      } else 
       $o[$options[$j]] = true; 
     } 
     $options = $o; 
     unset($o); 
    } 

    return $options; 
} 

function getDecodedStream($stream, $options) { 
    $data = ""; 
    if (empty($options["Filter"])) 
     $data = $stream; 
    else { 
     $length = !empty($options["Length"]) ? $options["Length"] : strlen($stream); 
     $_stream = substr($stream, 0, $length); 

     foreach ($options as $key => $value) { 
      if ($key == "ASCIIHexDecode") 
       $_stream = $this->decodeAsciiHex($_stream); 
      elseif ($key == "ASCII85Decode") 
       $_stream = $this->decodeAscii85($_stream); 
      elseif ($key == "FlateDecode") 
       $_stream = $this->decodeFlate($_stream); 
      elseif ($key == "Crypt") { // TO DO 
      } 
     } 
     $data = $_stream; 
    } 
    return $data; 
} 

function getDirtyTexts(&$texts, $textContainers) { 
    for ($j = 0; $j < count($textContainers); $j++) { 
     if (preg_match_all("#\[(.*)\]\s*TJ[\n|\r]#ismU", $textContainers[$j], $parts)) 
      $texts = array_merge($texts, array(@implode('', $parts[1]))); 
     elseif (preg_match_all("#T[d|w|m|f]\s*(\(.*\))\s*Tj[\n|\r]#ismU", $textContainers[$j], $parts)) 
      $texts = array_merge($texts, array(@implode('', $parts[1]))); 
     elseif (preg_match_all("#T[d|w|m|f]\s*(\[.*\])\s*Tj[\n|\r]#ismU", $textContainers[$j], $parts)) 
      $texts = array_merge($texts, array(@implode('', $parts[1]))); 
    } 

} 

function getCharTransformations(&$transformations, $stream) { 
    preg_match_all("#([0-9]+)\s+beginbfchar(.*)endbfchar#ismU", $stream, $chars, PREG_SET_ORDER); 
    preg_match_all("#([0-9]+)\s+beginbfrange(.*)endbfrange#ismU", $stream, $ranges, PREG_SET_ORDER); 

    for ($j = 0; $j < count($chars); $j++) { 
     $count = $chars[$j][1]; 
     $current = explode("\n", trim($chars[$j][2])); 
     for ($k = 0; $k < $count && $k < count($current); $k++) { 
      if (preg_match("#<([0-9a-f]{2,4})>\s+<([0-9a-f]{4,512})>#is", trim($current[$k]), $map)) 
       $transformations[str_pad($map[1], 4, "0")] = $map[2]; 
     } 
    } 
    for ($j = 0; $j < count($ranges); $j++) { 
     $count = $ranges[$j][1]; 
     $current = explode("\n", trim($ranges[$j][2])); 
     for ($k = 0; $k < $count && $k < count($current); $k++) { 
      if (preg_match("#<([0-9a-f]{4})>\s+<([0-9a-f]{4})>\s+<([0-9a-f]{4})>#is", trim($current[$k]), $map)) { 
       $from = hexdec($map[1]); 
       $to = hexdec($map[2]); 
       $_from = hexdec($map[3]); 

       for ($m = $from, $n = 0; $m <= $to; $m++, $n++) 
        $transformations[sprintf("%04X", $m)] = sprintf("%04X", $_from + $n); 
      } elseif (preg_match("#<([0-9a-f]{4})>\s+<([0-9a-f]{4})>\s+\[(.*)\]#ismU", trim($current[$k]), $map)) { 
       $from = hexdec($map[1]); 
       $to = hexdec($map[2]); 
       $parts = preg_split("#\s+#", trim($map[3])); 

       for ($m = $from, $n = 0; $m <= $to && $n < count($parts); $m++, $n++) 
        $transformations[sprintf("%04X", $m)] = sprintf("%04X", hexdec($parts[$n])); 
      } 
     } 
    } 
} 
function getTextUsingTransformations($texts, $transformations) { 
    $document = ""; 
    for ($i = 0; $i < count($texts); $i++) { 
     $isHex = false; 
     $isPlain = false; 

     $hex = ""; 
     $plain = ""; 
     for ($j = 0; $j < strlen($texts[$i]); $j++) { 
      $c = $texts[$i][$j]; 
      switch($c) { 
       case "<": 
        $hex = ""; 
        $isHex = true; 
        $isPlain = false; 
        break; 
       case ">": 
        $hexs = str_split($hex, $this->multibyte); // 2 or 4 (UTF8 or ISO) 
        for ($k = 0; $k < count($hexs); $k++) { 

         $chex = str_pad($hexs[$k], 4, "0"); // Add tailing zero 
         if (isset($transformations[$chex])) 
          $chex = $transformations[$chex]; 
         $document .= html_entity_decode("&#x".$chex.";"); 
        } 
        $isHex = false; 
        break; 
       case "(": 
        $plain = ""; 
        $isPlain = true; 
        $isHex = false; 
        break; 
       case ")": 
        $document .= $plain; 
        $isPlain = false; 
        break; 
       case "\\": 
        $c2 = $texts[$i][$j + 1]; 
        if (in_array($c2, array("\\", "(", ")"))) $plain .= $c2; 
        elseif ($c2 == "n") $plain .= '\n'; 
        elseif ($c2 == "r") $plain .= '\r'; 
        elseif ($c2 == "t") $plain .= '\t'; 
        elseif ($c2 == "b") $plain .= '\b'; 
        elseif ($c2 == "f") $plain .= '\f'; 
        elseif ($c2 >= '0' && $c2 <= '9') { 
         $oct = preg_replace("#[^0-9]#", "", substr($texts[$i], $j + 1, 3)); 
         $j += strlen($oct) - 1; 
         $plain .= html_entity_decode("&#".octdec($oct).";", $this->convertquotes); 
        } 
        $j++; 
        break; 

       default: 
        if ($isHex) 
         $hex .= $c; 
        elseif ($isPlain) 
         $plain .= $c; 
        break; 
      } 
     } 
     $document .= "\n"; 
    } 

    return $document; 
}}?>