Code Monkey home page Code Monkey logo

apex-xpath's Introduction

apex-xpath

A utility class for Salesforce Apex that lets you easily query an XML DOM structure using a simple subset of XPath syntax.

To Use

  1. Create a new XPath object from an XML string, or if you've already created a Dom.Document then pass that to the constructor.

  2. Call find, findFirst, getText, or getTextList, passing it an XPath expression and optionally a node from the DOM to start the search. (The default is to start the search at the root element).

XPath Syntax Supported

Apex-xpath supports a simple subset of XPath 1.0 "abbreviated" syntax.

An xpath consists of one or more location steps. Each location step starts with a "/" (except the initial step, if it's a relative path), a "node test", and an optional "predicate":

A node test is the part that specifies which tagnames to look for at a given point in the path:

  • /tagname The most common test is a plain tagname.
  • /* A tagname can be "*", meaning any immediate child.
  • /namespace:tagname You can include a namespace in the node test.
  • /tagname/tagname Paths can be up to 50 levels deep. (Limitation of Dom.Document class)
  • ./child/grandchild A tagname of "." refers to the current element.
  • ../sibling/nephew, ../../aunt/cousin A tagname of ".." refers to the current element's parent. Useful for getting siblings, cousins, etc.

A predicate is a filter expression inside "[ ]":

  • /tagname[1] Filter the results of the node test by "nth-result" (using 1-relative index)
  • /tagname[@id] Filter by "has this attribute"
  • /tagname[@id=12345] Filter by "attribute x = value"
  • /tagname[@id="12345"] Filter by "attribute x = value"

Example

String xml = some huge SOAP response containing orders;
XPath xp = new XPath(xml);
Dom.XmlNode[] orders = xp.find('/soapenv:Envelope/soapenv:Body/searchOrdersResponse/orders/order');

// If an order contains line items, here are a couple different ways to get their SKUs...
for (Dom.XmlNode order : orders) {
    String[] Skus = xp.getTextList(order, 'lineitem/id');
    String SkuCsv = xp.getText(order, ',', 'lineItem/id');
}

The Properties

Dom.Document doc

The Dom.Document that was passed in or that we created from the XML source.

Dom.XmlNode root

The root node in the Dom.Document.

The Methods

In all the methods below that take an optional start parameter, the default is to start the search at the root node.

XPath (String xmlsrc)

Creates an XPath object from a snippet of XML.

XPath (Dom.Document doc)

Creates an XPath object from a Dom.Document object that you've already created.

Dom.XmlNode[] find (String path)

Dom.XmlNode[] find (Dom.XmlNode start, String path)

Returns a List of all the nodes that are described by the path.

Dom.XmlNode findFirst (String path)

Dom.XmlNode findFirst (Dom.XmlNode start, String path)

Returns the first node in the DOM that is described by the path.

String getText (String path)

String getText (Dom.XmlNode start, String path)

Returns the string content of the first node in the DOM that is described by the path.

String getText (String delimiter, String path)

String getText (Dom.XmlNode start, String delimiter, String path)

Returns the string contents of all the nodes that are described by the path, separated by the delimiter.

String[] getTextList (String path)

String[] getTextList (Dom.XmlNode start, String path)

Returns the string contents of all the nodes that are described by the path, in a List.

Submitting Pull Requests

If you've fixed a bug or came up with a great addition to the API, I welcome your code submissions! To make things smoother, please follow these guidelines:

  • Create an Issue for the bug you're fixing or feature you're adding, if there isn't one already. This is especially important if you're adding a new feature or changing the API - the userbase needs to be able to discuss it first!
  • If someone is proposing a new feature or a change to the existing API, please chime in in the comments for that issue. It's important that the library evolves in a way that the userbase feels is useful and straightforward to use.
  • The default branch to submit pull requests to will normally be the current version under development. We'll try to release updates to Master in a controlled manner.
  • So far the project's coding conventions are rather straightforward:
    • K&R bracing (only because it's so ubiquitous, not because it's any good!).
    • Use the "[]" style when declaring Lists.
    • For each new method, write a comment block with a short description of what it does, what its parameters mean and their defaults, what it returns, and any caveats/gotchas/assumptions that the caller should know about.
    • If you're updating a method please review the comment block & update it if appropriate.

apex-xpath's People

Contributors

jennifersimonds avatar jennifersimondstableau avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

apex-xpath's Issues

Bug Reports

If you find any bugs in Apex-XPath, please report them here. And please add a minimal XML snippet that illustrates the bug if possible.

attribute reader

Hi @JenniferSimonds,
is it possible to use your apex-xpath for reading properties like "Name1/Name2/@Attribute" ?

I would like to read the Code property here.

<ISTATCode Code="20594/07" Type="C">Fabbricazione di prodotti chimici vari per uso industriale (inclusi i preparati antidetonanti e antigelo)</ISTATCode>

How can I accomplish it?

Thanks,
Claudio

Is Apex-XPath scalable enough?

Apex-XPath is based on the Dom.Document class. When this class parses an XML file, it constructs the whole DOM structure in memory, unlike XMLStreamReader. Because of this, there are bound to be practical limits on how large an XML file it can process.

Dom.Document imposes a limit of 50 nodes deep on the XML structure it can handle. (Although, so does XMLStreamReader, so maybe it's no less scalable?)

If there are limits to how big an XML file Dom.Document (and therefore Apex-XPath) can handle, do you know of any ways we could work around them?

Unit tests

I think my unit tests cover enough of the codebase, but maybe I'm missing something? Are there any bugs that the tests should've caught?

Enhancement: Other XPath features you'd like to see

Apex-XPath supports a simple core of XPath 1.0 syntax. I think it occupies the sweet spot between simplicity and comprehensiveness. It's simple enough to cover maybe 95% of your use cases directly. For the other 5%, Apex-XPath takes you close enough that you can finish filtering the results with minimal effort by using the standard Dom.Document & XmlNode classes.

So far it has covered 100% of my use cases, but I want to know if there are any features of XPath you've found yourself wishing it would support directly. Is there anything we could add to it that would greatly simplify your projects? Or should we keep the library nice & simple, and anything more would just give us diminshing returns of needless complexity?

Day 1: works like a charm, Day 2: Timeouts - Salesforce Penalities?

I discovered your awesome lib while looking for a way to parse a 1 MB Metadata API WSDL in Apex. I made it work and it was lightning fast. But today I just get timeouts in my scratch org.

HttpRequest request = new HttpRequest();
request.setEndpoint(URL.getOrgDomainUrl().toExternalForm() + '/services/wsdl/metadata');
request.setMethod('GET');
request.setHeader('Cookie','sid=' + UserInfo.getSessionId());
request.setHeader('Content-Type', 'application/xml');

Blob wsdl = new Http().send(request).getBodyAsBlob();
XPath schema = new XPath( wsdl.toString() );

System.debug( SCHEMA.find('/definitions/types/xsd:schema/xsd:complexType').size() );

Also asked a question on StackExchange https://salesforce.stackexchange.com/q/353924/256

Is getText with delimiter really necessary?

Calling getText(xpath) returns the text of the first node that matches the xpath, calling getText(delimiter, xpath) returns a string that's a delimited list of node contents, and getTextList returns a List.

I've found that I don't ever use getText with delimiter; I always call getTextList & iterate thru the String[] result. So, is getText(delimiter, xpath) really necessary?

We can't define two getText's, one that returns a single String and another that returns a String[], so I think we're stuck having two differently-named methods for these. But maybe we should just deprecate the delimited-list version?

Let us know if you find it useful to you and it should be kept.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.