Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   XML (https://www.delphipraxis.net/46-xml/)
-   -   XML Knoten holen (https://www.delphipraxis.net/213462-xml-knoten-holen.html)

creehawk 2. Aug 2023 18:48

XML Knoten holen
 
Folgende XML (Auszug)

Code:
<AssetsList>
<Asset>
 <Template>Chain</Template>
 <Values>
  <Standard>
   <GUID>137596</GUID>
   <Name>chain 08</Name>
  </Standard>
 <ProductionChain>
  <Building>135669</Building>
   <Tier1>
    <Item>
     <Building>101415</Building>
     <Tier2>
      <Item>
       <Building>101272</Building>
      </Item>
     </Tier2>
    </Item>
    <Item>
     <Building>135224</Building>
      <Tier2>
       <Item>
        <Building>1010331</Building>
       </Item>
       <Item>
        <Building>134614</Building>       <<<<<<<<
       </Item>
       <Item>
        <Building>135134</Building>
          <Tier3>
            <Item>
             <Building>101260</Building>
            </Item>
            <Item>
             <Building>101270</Building>
            </Item>
          </Tier3>
        </Item>
      </Tier2>
     </Item>
  </Tier1>
</ProductionChain>
</Values>
</Asset>

........
</Assetlist>



Hier suche ich jetzt zum Beispiel den Knoten <Building>134614</Building> oder besser den Wert. Kein Problem.
Jetzt benötige ich aber den Wert des Knotens <GUID>. (Asset/Values/Standard/GUID) ParentNode geht da nicht, das Beispiel ist eines von Dutzenden mit unterschiedlicher Tiefe.

Wie komme ich dahin?

Da fehlt's bei mir.

xreehawk

himitsu 2. Aug 2023 19:32

AW: XML Knoten holen
 
Zitat:

Zitat von creehawk (Beitrag 1525179)
Hier suche ich jetzt zum Beispiel den Knoten <Building>134614</Building> oder besser den Wert. Kein Problem.
Jetzt benötige ich aber den Wert des Knotens <GUID>. (Asset/Values/Standard/GUID) ...

Meinst du das nicht andersrum?
* das eine <GUID> ist problemlos einfach
* einer der, bzw. alle <Building> wird etwas schwerer

Zum Thema Bei Google suchenXPath finden sich genügend Erklärungen und Hilfen.
Auch gibt es nette Programme und auch Online-Seiten, wo man gemütlich ausprobieren kann und sich teilweise auch Pfade generieren lassen kann.
Bei Google suchenXPath online

Vielleicht?
Delphi-Quellcode:
/Asset/Values/ProductionChain/Tier1/Item[2]/Tier2/Item[2]/Building

oder
Delphi-Quellcode:
/Asset/Values[Standard/GUID=137596]/ProductionChain/Tier1/Item[2]/Tier2/Item[2]/Building

oder
Delphi-Quellcode:
//ProductionChain[../Standard/GUID=137596]/Tier1/Item[2]/Tier2/Item[2]/Building

...

creehawk 3. Aug 2023 05:45

AW: XML Knoten holen
 
Moin.

Also: der obige XML Auszug ist der Teile eine XML mit insgesamt 93 solcher Blöcke.

Gegeben ist mir ein String : 134614

Diesen String suche ich in der gesamten XML. Er wird mit Sicherheit in einem dieser 93 Blöcke zu finden sein.

Und von diesen Block benötige ich dann die <GUID>.

Direkte Pfade kann ich vergessen, jeder der besagten Blöcke hat eine andere Tiefe, wie schon gesagt.

creehawk

bcvs 3. Aug 2023 07:12

AW: XML Knoten holen
 
Kannst du dich nicht von dem gefundenen Knoten über die ParentNodes hochhangeln bis <Asset> und von da aus Values/Standard/GUID auslesen?

creehawk 3. Aug 2023 08:12

AW: XML Knoten holen
 
Natürlich kann ich das.

Nur ist für fast jeden der Blöcke eine andere parentabfrage zu machen.

Geht das nicht einfacher?

creehawk

creehawk 3. Aug 2023 10:34

AW: XML Knoten holen
 
So geht's..... als MischMasch aus XML und Strings.:oops:

Delphi-Quellcode:
begin
  ChainTexts := TStringlist.Create;
  ResultStrings := TStringlist.Create;
  ChainList := CoDOMDocument.create;
  ChainList.Load(ORGPath + 'ProductionChain.xml');
  ChainRoot := ChainList.DocumentElement;
  ChainUnits := ChainRoot.childNodes; // 128 Einträge
  BuildingShortList  := CoDOMDocument.create;
  BuildingShortList.Load(XMLPath + 'BuildingsShort.xml');
  BuildingShortRoot := BuildingShortList.DocumentElement;
  BuildingShortNodes := BuildingShortRoot.childNodes; // 207 Einträge
  for I := 0 to BuildingShortNodes.Length-1 do
   begin
   GUID := BuildingShortNodes.item[I].attributes[0].text;
   for II := 0 to Chainunits.length-1 do
     begin
      ChainTexts := TStringlist.Create;
      ChainGUID := ChainUnits.item[II].SelectSingleNode('Values/Standard/GUID').text;
      ChainTexts.Add(ChainUnits.item[II].XML);
      for III:= 0 to ChainTexts.Count -1 do
        begin
          if AnsiPos(GUID, ChainTexts.Strings[III]) > 0 then ResultStrings.Add(ChainGUID + '#' + GUID)
        end;
     end;
  end;
  ResultStrings.SaveToFile(TMPPath + 'ChainGUIDs.txt');
end;
Aber schön ist anders.:cry:

creehawk

himitsu 3. Aug 2023 11:57

AW: XML Knoten holen
 
Pos, AnsiPos oder sowas "unverständliches"

Delphi-Referenz durchsuchenSameStr (OK, das ist ein =), Delphi-Referenz durchsuchenSameText, Delphi-Referenz durchsuchenStartsStr, StartsText, Delphi-Referenz durchsuchenContainsStr, ContainsText uvm.

Warum überhaupt Pos?
Also warum ein Contains?
Wenn du nach 12345 suchts und dann auch 01234567 findets. :freak:


Wie in den Beispielen in #2 zu sehen, kann man im XPath auch Parameter, Parents, Childs, Siblings usw. prüfen. (darüber, darunter, daneben und sonstwo)
Auch kann man absolut, relativ oder komplett frei suchen.

mytbo 3. Aug 2023 15:44

AW: XML Knoten holen
 
Zitat:

Zitat von creehawk (Beitrag 1525201)
So geht's..... als MischMasch aus XML und Strings.

Hast du die Wahl des Datenformats? JSON lässt sich einfacher verarbeiten. Wenn die Struktur nicht kompliziert ist, dann kannst du das XML auch einfach parsen:
Delphi-Quellcode:
function FindBuildingGUID(pmXMLStream: TStream; const pmcSearchBuilding: String): String; overload;
begin
  Result := '';
  if pmXMLStream = Nil then Exit; //=>
  if pmcSearchBuilding = '' then Exit; //=>

  var xmlSize: Int64 := pmXMLStream.Size;
  if (xmlSize > 0) and (xmlSize < High(NativeInt)) then
  begin
    var parser: TParser := TParser.Create(pmXMLStream);
    try
      var runGUID: String;
      while parser.SourcePos < xmlSize do
      begin
        if parser.Token = '<' then
        begin
          parser.NextToken;
          if parser.Token = '/' then
          begin
            repeat
              parser.NextToken;
            until parser.Token = '>';
          end
          else if parser.TokenSymbolIs('GUID') then
          begin
            parser.NextToken; // '>' closing tag
            parser.NextToken; // XML tag value
            runGUID := parser.TokenString;
          end
          else if parser.TokenSymbolIs('BUILDING') then
          begin
            parser.NextToken; // '>' closing tag
            parser.NextToken; // XML tag value
            if SameText(parser.TokenString, pmcSearchBuilding) then
              Exit(runGUID); //=>
          end;
        end;

        parser.NextToken;
      end;
    finally
      parser.Free;
    end;
  end;
end;

function FindBuildingGUID(const pmcXMLData, pmcSearchBuilding: String): String; overload;
begin
  Result := '';
  if pmcXMLData = '' then Exit; //=>
  if pmcSearchBuilding = '' then Exit; //=>

  var stream: TStringStream := TStringStream.Create(pmcXMLData);
  try
    Result := FindBuildingGUID(stream, pmcSearchBuilding);
  finally
    stream.Free;
  end;
end;

// Functions AnyTextFileToString, MakePath are from mORMot library.
// Required Units: mormot.core.text, mormot.core.unicode, mormot.core.os
begin
  var xml: String := AnyTextFileToString(MakePath([Executable.ProgramFilePath, 'daten.xml']));
  ShowMessage(Format('GUID: %s', [FindBuildingGUID(xml, '134614')]));
Lösung ohne Gewähr. Die Funktion AnyTextFileToString beachtet das Format und konvertiert, wenn es notwendig ist. MakePath verkettet zu einem Pfad unter Berücksichtigung des OS. TExecutable ist eine Datenstruktur (Record) mit nützlichen Variablen zur sofortigen Verwendung.

Bis bald...
Thomas

creehawk 3. Aug 2023 16:00

AW: XML Knoten holen
 
Nein, ich muss auf XML arbeiten.

Und AnsiPos muss jetzt nicht sein, ok, aber das war jetzt auch erstmal die Lösung die mir so einfiel.....

Lass ich jetzt auch so, vielen Dank in jedem Fall für die Hinweise und Ideen,

creehawk

himitsu 3. Aug 2023 16:24

AW: XML Knoten holen
 
Wie gesagt, beim
Delphi-Quellcode:
if AnsiPos(GUID, ChainTexts.Strings[III]) > 0 then

aka
Delphi-Quellcode:
if ContainsStr(ChainTexts.Strings[III], GUID) then
(ja, das wurde saublöd vom C# geklaukopiert und man muß auf die Parameter-Reihenfolge achten)

dabei hätte ich eher das Gehühl, als wenn eigentlich Folgendes
Delphi-Quellcode:
if SameStr(GUID, ChainTexts.Strings[III]) then

aka
Delphi-Quellcode:
if GUID = ChainTexts.Strings[III] then

"gemeint" war.



Und zusätzlich war's nur noch als Tipp, dass man Code auch "sprechend" schreiben kann, so dass er direkt sagt, was er eigentlich macht.
Delphi-Quellcode:
a=b
aka
Delphi-Quellcode:
SameStr
(ja, prinzipiell sieht SameStr erstmal nutzlos aus, aber nicht, wenn man es in Bezug auf die anderen Funktionen betrachtet)
Delphi-Quellcode:
Pos()=0
aka
Delphi-Quellcode:
not ContainsStr()
oder
Delphi-Quellcode:
not StartsStr()

Delphi-Quellcode:
Pos()=1
aka
Delphi-Quellcode:
StartsStr()

Delphi-Quellcode:
Pos()<>0
aka
Delphi-Quellcode:
ContainsStr()


Delphi-Quellcode:
AnsiLowerCase(a)=AnsiLowerCase(b)
aka
Delphi-Quellcode:
SameText

Delphi-Quellcode:
Pos(AnsiLowerCase())=0
aka
Delphi-Quellcode:
not ContainsText()
oder
Delphi-Quellcode:
not StartsText()

Delphi-Quellcode:
Pos(AnsiLowerCase())=1
aka
Delphi-Quellcode:
StartsText()

Delphi-Quellcode:
Pos(AnsiLowerCase())<>0
aka
Delphi-Quellcode:
ContainsText()


Links muß man auf leicht übersehbare Kleinigkeiten achten, aber Rechts steht es verständlich da.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:31 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz