Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
 IXMLDOMDocument3 validatenode в delphi7 не работает  [new]
evgen29
Member

Откуда:
Сообщений: 140
Здравствуйте! Валидировал свой xml с помощью xsd-схемы и объекта IXMLDOMDocument3 метод validate. Нормально валидировалось или выдавало ошибку. Но возникла необходимость удалять строки, в которых есть несоответствие xsd-схеме. Доходит до vXMLParserError :=vXMLDoc.validateNode(line);
и выдает ошибку EOleException with message 'Неизвестное имя'

+ Код
function TfrmSetFormat.ValidatePrice(f: string): boolean;
var
  vXMLParserError: IXMLDOMParseError;
  vXMLSchema: IXMLDOMSchemaCollection2;
  vXMLDoc: IXMLDOMDocument3;
  vXMLSchemaDoc: IXMLDOMDocument3;
  vStrs: TStringList;
  i, j: integer;
  str: string;
  line: IXMLDOMNode;
  lines: IXMLDOMNodeList;
  ws: Widestring;
begin
  result := false;
  vStrs := TStringList.Create();
  try
    //Загрузка схемы
    vXMLSchema := CoXMLSchemaCache60.Create();
    vXMLSchemaDoc := CoDOMDocument60.Create();
    vXMLSchemaDoc.async:=False;
    //vXMLSchemaDoc.load(localdir + 'farmsm\' + formattypedir + '\out.xsd');
    vStrs.LoadFromFile(localdir + 'farmsm\' + formattypedir + '\out.xsd');
    ws:=StringReplace(UTF8Decode(vStrs.Text),#13#10,'',[rfReplaceAll,rfIgnoreCase]);

    vXMLSchemaDoc.loadXML(ws);
    if vXMLSchemaDoc.parseError.errorCode <> 0 then
    begin
      ShowMessage(Format('Ошибка при загрузке схемы <%s: %s>', [vXMLSchemaDoc.parseError.reason, vXMLSchemaDoc.parseError.srcText]));
      Exit;
    end;
    vXMLSchema.add('', vXMLSchemaDoc);

    //Загрузка документа
    vXMLDoc := CoDOMDocument60.Create();
    vXMLDoc.async := False;
    vXMLDoc.resolveExternals := false;
    vXMLDoc.validateOnParse := false;
    //vXMLDoc.load(f);
    vStrs.Clear;
    vStrs.LoadFromFile(f);
    vStrs.Text:='<?xml version="1.0" encoding="UTF-8"?>'+vStrs.Text;
    ws:=UTF8Decode(vStrs.Text);
    vXMLDoc.loadXML(ws);

    vXMLDoc.schemas := vXMLSchema;

    lines := vXMLDoc.getElementsByTagName('line');
    line := lines.nextNode;
    j := 0;
    i := 0;
    while line <> nil do
    begin
      vXMLParserError := vXMLDoc.validateNode(line);
      if vXMLParserError<>nil then
      begin
      if vXMLParserError.errorCode <> 0 then
      begin
        str := Format('Ошибка при валидации <Причина: %s; Текст: %s; Код: %d>', [Trim(vXMLParserError.reason),
          vXMLParserError.srcText, vXMLParserError.errorCode]);
        vXMLDoc.removeChild(line);
        j := j + 1;
      end;
      end;
      i := i + 1;
      line := lines.nextNode;
    end;

    if vXMLDoc.getElementsByTagName('line').length = 0 then
      ShowMessage(Format('Все строки содержат ошибки. Последняя ошибка: %s', [str]))
    else
    begin
      ShowMessage(Format('Удалено %d строк с ошибками, осталось %d строк. Последняя ошибка: %s', [j, i - j, str]));
      ShowMessage('Валидация документа прошла успешно');
      result := true;
    end;
  finally
    FreeAndNil(vStrs);
  end;
end;


+ xsd-схема:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="output" type="outputType">
  </xs:element>

  <xs:complexType name="outputType">
    <xs:sequence>
      <xs:element name="header" type="headerType"/>
      <xs:element name="body" type="bodyType"/>
    </xs:sequence>    
  </xs:complexType>
  
  <xs:complexType name="headerType">
    <xs:all>
    </xs:all>    
  </xs:complexType>
  <xs:complexType name="bodyType">
    <xs:sequence minOccurs="1" maxOccurs="unbounded">
      <xs:element name="line" type="lineBodyType"/>
    </xs:sequence>   
  </xs:complexType>
  
  <xs:complexType name="lineBodyType">
    <xs:all>
	  <!--Секция описания прайс-листа-->
      <xs:element name="CODEPST" type="CType24" minOccurs="0" maxOccurs="1"/>
      <xs:element name="NAME" type="CType128" minOccurs="0" maxOccurs="1"/>
      <xs:element name="PROD" type="CType64" minOccurs="0" maxOccurs="1"/>
      <xs:element name="COUNTRY" type="CType32" minOccurs="0" maxOccurs="1"/>
      <xs:element name="MINZAK" type="NType9" minOccurs="0" maxOccurs="1"/>
      <xs:element name="MINKRATN" type="NType9" minOccurs="0" maxOccurs="1"/>
      <xs:element name="VALID" type="CType10" minOccurs="0" maxOccurs="1"/>
      <xs:element name="OSTATOK" type="NType9" minOccurs="0" maxOccurs="1"/>
      <xs:element name="EAN13" type="CType13" minOccurs="0" maxOccurs="1"/>
      <xs:element name="GNVLS" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
      <xs:element name="EDUP" type="CType12" minOccurs="0" maxOccurs="1"/>
      <xs:element name="PACK" type="NType9" minOccurs="0" maxOccurs="1"/>
      <xs:element name="REGPR" type="NType15_4" minOccurs="0" maxOccurs="1"/>
      <xs:element name="PRODPR" type="NType15_4" minOccurs="0" maxOccurs="1"/>
      <xs:element name="VAT" type="NType9" minOccurs="0" maxOccurs="1"/>
      <xs:element name="MARKER" type="CType16" minOccurs="0" maxOccurs="1"/>
      <xs:element name="PRICE" type="NType15_4" minOccurs="1" maxOccurs="1"/>
      <xs:element name="UID" type="CType50" minOccurs="0" maxOccurs="1"/>
    </xs:all>    
  </xs:complexType>  
  
   <xs:simpleType name="NType">
      <xs:restriction base="xs:decimal">
         <xs:minInclusive value="0"/>
		 <xs:fractionDigits value="0"/>
      </xs:restriction>
   </xs:simpleType>    
   <xs:simpleType name="NType15_4">
      <xs:restriction base="xs:string">
         <xs:pattern value="[+-]?\d{1,15}([.,]\d{1,4})?"/>
         <xs:maxLength value="21"/>
      </xs:restriction>
   </xs:simpleType>        
   <xs:simpleType name="NType8_4">
      <xs:restriction base="xs:string">
         <xs:pattern value="[+-]?\d{1,8}([.,]\d{1,4})?"/>
         <xs:maxLength value="14"/>
      </xs:restriction>
   </xs:simpleType>          
   <xs:simpleType name="NType10">
      <xs:restriction base="NType">
         <xs:maxInclusive value="999999999"/>
		 <xs:totalDigits value="9"/>
      </xs:restriction>
   </xs:simpleType>     
   <xs:simpleType name="NType9">
      <xs:restriction base="NType">
         <xs:maxInclusive value="999999999"/>
		 <xs:totalDigits value="9"/>
      </xs:restriction>
   </xs:simpleType>  
   <xs:simpleType name="NType5">
      <xs:restriction base="NType">
         <xs:maxInclusive value="99999"/>
		 <xs:totalDigits value="5"/>
      </xs:restriction>
   </xs:simpleType>  
   <xs:simpleType name="NType3">
      <xs:restriction base="NType">
         <xs:maxInclusive value="999"/>
		 <xs:totalDigits value="3"/>
      </xs:restriction>
   </xs:simpleType>     
   <xs:simpleType name="NType2">
      <xs:restriction base="NType">
         <xs:maxInclusive value="99"/>
		 <xs:totalDigits value="2"/>
      </xs:restriction>
   </xs:simpleType>  
   <xs:simpleType name="NType1">
      <xs:restriction base="NType">
         <xs:maxInclusive value="9"/>
		 <xs:totalDigits value="1"/>
      </xs:restriction>
   </xs:simpleType>  
   <xs:simpleType name="DType">
      <xs:restriction base="xs:string">
         <xs:pattern value="\d{2}[.]\d{2}[.]\d{4}"/>
         <xs:maxLength value="10"/>	  
      </xs:restriction>
   </xs:simpleType>  
   <xs:simpleType name="TType">
      <xs:restriction base="xs:time">
         <xs:pattern value="hh:mm:ss"/>
      </xs:restriction>
   </xs:simpleType>     
   <xs:simpleType name="CType2">
      <xs:restriction base="xs:string">
         <xs:minLength value="0"/>
         <xs:maxLength value="2"/>
      </xs:restriction>
   </xs:simpleType>     
   <xs:simpleType name="CType16">
      <xs:restriction base="xs:string">
         <xs:minLength value="0"/>
         <xs:maxLength value="16"/>
      </xs:restriction>
   </xs:simpleType>        
   <xs:simpleType name="CType8">
      <xs:restriction base="xs:string">
         <xs:minLength value="0"/>
         <xs:maxLength value="8"/>
      </xs:restriction>
   </xs:simpleType>        
   <xs:simpleType name="CType24">
      <xs:restriction base="xs:string">
         <xs:minLength value="0"/>
         <xs:maxLength value="24"/>
      </xs:restriction>
   </xs:simpleType>           
   <xs:simpleType name="CType64">
      <xs:restriction base="xs:string">
         <xs:minLength value="0"/>
         <xs:maxLength value="64"/>
      </xs:restriction>
   </xs:simpleType>           
   <xs:simpleType name="CType128">
      <xs:restriction base="xs:string">
         <xs:minLength value="0"/>
         <xs:maxLength value="128"/>
      </xs:restriction>
   </xs:simpleType>           
   <xs:simpleType name="CType254">
      <xs:restriction base="xs:string">
         <xs:minLength value="0"/>
         <xs:maxLength value="254"/>
      </xs:restriction>
   </xs:simpleType>              
   <xs:simpleType name="CType32">
      <xs:restriction base="xs:string">
         <xs:minLength value="0"/>
         <xs:maxLength value="32"/>
      </xs:restriction>
   </xs:simpleType>      
   <xs:simpleType name="CType12">
      <xs:restriction base="xs:string">
         <xs:minLength value="0"/>
         <xs:maxLength value="12"/>
      </xs:restriction>
   </xs:simpleType>       
   <xs:simpleType name="CType13">
      <xs:restriction base="xs:string">
         <xs:minLength value="0"/>
         <xs:maxLength value="13"/>
      </xs:restriction>
   </xs:simpleType>              
   <xs:simpleType name="CType10">
      <xs:restriction base="xs:string">
         <xs:minLength value="0"/>
         <xs:maxLength value="10"/>
      </xs:restriction>
   </xs:simpleType>       
   <xs:simpleType name="CType50">
      <xs:restriction base="xs:string">
         <xs:minLength value="0"/>
         <xs:maxLength value="50"/>
      </xs:restriction>
   </xs:simpleType>  

   <xs:simpleType name="Currency">
      <xs:restriction base="xs:string">
         <xs:enumeration value="USD"/>
         <xs:enumeration value="EUR"/>
      </xs:restriction>
   </xs:simpleType>   
</xs:schema>  


сам xml:
<output><header></header><body>
<line><NAME>Курносики Бальзам для детей и взрослых "Пантенол ZD" , 75 мл.</NAME><COUNTRY>РОССИЯ</COUNTRY><PROD>ЗАО "Зеленая дубрава"</PROD>
<OSTATOK>9</OSTATOK><VALID>01.01.2022</VALID><PRICE>91.99</PRICE><EAN13>4605658403133</EAN13><CODEPST>40313</CODEPST>
</line>
<line><NAME>Курносики Бальзам для детей и взрослых "Пантенол ZD" , 75 мл.</NAME><COUNTRY>РОССИЯ</COUNTRY><PROD>ЗАО "Зеленая дубрава"</PROD>
<OSTATOK>24</OSTATOK><VALID>01.07.2022</VALID><PRICE>91.99</PRICE><EAN13>4605658403133</EAN13><CODEPST>40313</CODEPST></line>
...
</body></output>


Сообщение было отредактировано: 17 мар 20, 18:20
17 мар 20, 13:04    [22100567]     Ответить | Цитировать Сообщить модератору
 Re: IXMLDOMDocument3 validatenode в delphi7 не работает  [new]
goldmi45
Member

Откуда:
Сообщений: 1234
evgen29,

А если посмотреть, что в lines и в line, может тогда будет понятней, почему возникает ошибка?
17 мар 20, 14:25    [22100659]     Ответить | Цитировать Сообщить модератору
 Re: IXMLDOMDocument3 validatenode в delphi7 не работает  [new]
evgen29
Member

Откуда:
Сообщений: 140
goldmi45
evgen29,

А если посмотреть, что в lines и в line, может тогда будет понятней, почему возникает ошибка?


так validate проходит нормально, даже если я не убираю ошибки. vXMLParserError.errorCode просто не 0 становится и есть описание ошибки.
Попробовал на документе, где нет ошибок. Validate проходит, validatenode опять тоже самое. Не в этом дело.

Сообщение было отредактировано: 17 мар 20, 16:26
17 мар 20, 16:26    [22100750]     Ответить | Цитировать Сообщить модератору
 Re: IXMLDOMDocument3 validatenode в delphi7 не работает  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11602
Вот этот кусок
evgen29
    vStrs.LoadFromFile(f);
    vStrs.Text:='<?xml version="1.0" encoding="UTF-8"?>'+vStrs.Text;
    ws:=UTF8Decode(vStrs.Text);
    vXMLDoc.loadXML(ws);
мне сильно не нравится. В чем смысл таких приседаний? Сам XML в какой кодировке сохранен?
17 мар 20, 17:13    [22100792]     Ответить | Цитировать Сообщить модератору
 Re: IXMLDOMDocument3 validatenode в delphi7 не работает  [new]
evgen29
Member

Откуда:
Сообщений: 140
в общем дело не в этом.Дело в том, что почему-то в delphi 7 эта опция работает не так.
Сделал через ole. Не ругается на validateNode(line); если я убираю цикл, т.е. методы работают нормально.
Такое впечатление, что для delphi 7 в модуле MSXML2_TLB этот метод как-то неправильно скомпилирован или не туда указывает

ps:
Сейчас ругается на несовместимость типов при самом сравнении, пытаюсь победить.
Если знаете подскажите. line по ходу содержит IDispatch и когда исчерпаны все линии выдает $00000000. Но при сравнении ругается. Пробовал и так while line<>$00000000 do и так
while line<>Unassigned do


function TfrmSetFormat.ValidatePrice(f: string): boolean;
var
  vXMLParserError: OleVariant;
  vXMLSchema: OleVariant;
  vXMLDoc: OleVariant;
  vStrs: TStringList;
  i, j: integer;
  str: string;
  line: Variant;
  lines: Variant;
  ws: Widestring;
begin
  result := false;
  OleInitialize(nil);
  try
    //Загрузка схемы
    vXMLSchema := CreateOleObject('MSXML2.XMLSchemaCache.6.0');
    vXMLSchema.add('', localdir + 'farmsm\' + formattypedir + '\out.xsd');
    //Загрузка документа
    vXMLDoc := CreateOleObject('MSXML2.DOMDocument.6.0');
    vXMLDoc.async := False;
    vXMLDoc.resolveExternals := false;
    vXMLDoc.validateOnParse := false;
    vXMLDoc.schemas := vXMLSchema;
    vXMLDoc.load(f);
    lines := vXMLDoc.selectNodes('//line');
    line := lines.nextNode;
    j := 0;
    i := 0;
    while line<>Unassigned do
    begin
      vXMLParserError := vXMLDoc.validateNode(line);
      //if vXMLParserError<>Null then
      //begin
      if vXMLParserError.errorCode <> 0 then
      begin
        str := Format('Ошибка при валидации <Причина: %s; Текст: %s; Код: %d>', [Trim(vXMLParserError.reason),
          vXMLParserError.srcText, vXMLParserError.errorCode]);
        vXMLDoc.removeChild(line);
        j := j + 1;
      end;
      //end;
      i := i + 1;
      line := lines.nextNode;
    end;

    if vXMLDoc.getElementsByTagName('line').length = 0 then
      ShowMessage(Format('Все строки содержат ошибки. Последняя ошибка: %s', [str]))
    else
    begin
      ShowMessage(Format('Удалено %d строк с ошибками, осталось %d строк. Последняя ошибка: %s', [j, i - j, str]));
      ShowMessage('Валидация документа прошла успешно');
      result := true;
    end;
  finally
    OleUnInitialize;
  end;
end;
17 мар 20, 17:51    [22100822]     Ответить | Цитировать Сообщить модератору
 Re: IXMLDOMDocument3 validatenode в delphi7 не работает  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 11602
while (line as IDispatch) <> nil do


PS В аттаче мой рабочий MSXML

К сообщению приложен файл (MSXML2_TLB.pas.zip - 20Kb) cкачать
17 мар 20, 18:06    [22100834]     Ответить | Цитировать Сообщить модератору
 Re: IXMLDOMDocument3 validatenode в delphi7 не работает  [new]
evgen29
Member

Откуда:
Сообщений: 140
В общем может кому понадобится рабочий вариант по удалению строк, не проходящих проверку. Сейчас пока так, removeChild не отработал, ругается, что нет такого потомка. Но он вложенный, видимо там вложенных не находит метод. Потом при рефакторинге исправлю.
function TfrmSetFormat.ValidatePrice(f: string): boolean;
var
  vXMLParserError: OleVariant;
  vXMLSchema: OleVariant;
  vXMLDoc: OleVariant;
  //vStrs: TStringList;
  i, j: integer;
  str: string;
  line: OleVariant;
  lines: OleVariant;
  ws, xml: Widestring;
  //d: IXMLDOMNodeList; //;
begin
  result := false;
  OleInitialize(nil);
  try
    //Загрузка схемы
    vXMLSchema := CreateOleObject('MSXML2.XMLSchemaCache.6.0');
    vXMLSchema.add('', localdir + 'farmsm\' + formattypedir + '\out.xsd');
    //Загрузка документа
    vXMLDoc := CreateOleObject('MSXML2.DOMDocument.6.0');
    vXMLDoc.async := False;
    vXMLDoc.resolveExternals := false;
    vXMLDoc.validateOnParse := false;
    vXMLDoc.schemas := vXMLSchema;
    vXMLDoc.load(f);
    lines := vXMLDoc.selectNodes('//line');
    line := lines.nextNode;
    j := 0;
    i := 0;
    while IDispatch(line) <> nil do
    begin
      vXMLParserError := vXMLDoc.validateNode(line);
      //if vXMLParserError<>Null then
      //begin
      if vXMLParserError.errorCode <> 0 then
      begin
        str := Format('Ошибка при валидации <Причина: %s; Текст: %s; Код: %s; Линия: %d>', [Trim(vXMLParserError.reason),
          vXMLParserError.srcText, vXMLParserError.errorCode, integer(i + 1)]);
        line.text := '';
        j := j + 1;
      end;
      //end;
      i := i + 1;
      line := lines.nextNode;
    end;
    xml := StringReplace(vXMLDoc.XML, '<line></line>', '', [rfReplaceAll, rfIgnoreCase]);
    if i = j then
      ShowMessage(Format('Все строки содержат ошибки. Последняя ошибка: %s', [str]))
    else
    begin
      if j > 0 then
      begin
        ShowMessage(Format('Удалено %d строк с ошибками, осталось %d строк. Последняя ошибка: %s', [j, i - j, str]));
        ShowMessage('Валидация документа прошла успешно частично.' + #13#10 + 'Ошибочные строки будут удалены при обработке автоматически.');
      end else
        ShowMessage('Валидация документа прошла полностью успешно');
      result := true;
    end;
  finally
    OleUnInitialize;
  end;
end;
17 мар 20, 21:57    [22100967]     Ответить | Цитировать Сообщить модератору
Все форумы / Delphi Ответить